/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
// Interpreter.cpp: implementation of the CInterpreter class.
//
//////////////////////////////////////////////////////////////////////

#include "ssi_interpreter.h"
#include "ssi_status.h"
#include "ssi_statement.h"
#include "ssi_conditional.h"
#include "ssi_scriptline.h"
#include "ssi_datatypes.h"

#define ZAP_ENGINE Engine = oldEng; delete anEng;

#include "ssi_input.h"
#include "ssi_script.h"
#include "ssi_functioninput.h"
#include "ssi_interpreter.h"
#include "ssi_internals.h"
#include "ssi_interpreter.h"
//#include "ssi_tnode2.h"

//////////////////////////////////////////////////////////////
//
//  So... Script control should be handled by the Interpreter?
//    This may make sense in terms of flow control....
//    However, functions should be made of statements in the
//    Engine.  Perhaps flow control should be made of statements
//    in the Engine as well?  Where is the control decision
//    made?  The Interpreter certainly must make the statement
//    set from the function and flow control.  There could be 
//    a StatementNode, StatementTree set... both of which are 
//    used for both flow controls and functions.
//
//    Now, what is the difference?  Could both Flow and Functions
//    be constructed the same?  The only difference being that
//    Functions are run once (with accesses to what?) from an 
//    external source, and Flows are run multiple times from an
//    external source.  What is the external source?  TBD... 
//    either Interpreter or Engine.  One problem with this is 
//    what to do with if/elseif/else and switch statements?  Each
//    condition is a separate StatementTree?  And externally it is
//    decided what to do with each.  
//
//    So, to make these decisions, should there a sort of decision
//    class?  Each with a set of inputs?  The decision class will be
//    subclassed into different conditions, including for, while, etc.
//
//    I think that the Interpreter will be responsible for creating the
//    decision class and the associated StatementTrees.  From this a 
//    master statement is created, whereby it is passed to the engine for
//    execution.  Part of the StatementTree can be other StatementTrees
//    for nested flow control.
//
//    In fact, the entire script should be a StatementTree, thereby
//    allowing pre-parsing and error detection prior to script
//    execution.  This will only be the case for script exection, not
//    normal command line execution.  Command line execution will handle
//    flow strictly via the Interpreter and Console.  In fact, the console
//    should stay out of it, and the Interpreter should handle its state
//    alone.
//
//    Should Functions have the same structure?  A function can have
//    the StatementTree like flow control, but it runs differently.  A
//    function will be loaded via the interpreter and set as a
//    StatementTree.  Note that a function loaded should be searched
//    for in the Engine so functions arent loaded multiple times.  That
//    means in order to search for a function, it must have a type.  In
//    fact, functions should be a separate set than the Flow nodes so 
//    they can be searched and so that Functions can contain Flows and
//    Flows can call functions.  User defined functions should be a
//    subclass of the CFunction class and added to the function set
//    identically.  Then the interpreter has to do no additional
//    work to find and run the function.  This also handles how to pass
//    parameters to the function and handle return values.
//
//    In order for this StatementTree stuff to work, the Evaluate function
//    in CInterpreter must be re-designed to only create statements of 
//    various types.  These statements must be handled by CEngine.  Therefore,
//    CEngine must be able to handle many types of Statements.  This makes 
//    sense, since CEngine should handle all actions (including creating 
//    Variables and assigning values) via statements, leaving CInterpreter
//    to handle all syntax issues and create statements only.

//  We already have a script array (Console can convert one if necessary).
//  So, what if we set an execution pointer?  In this case, how does a 
//  regular language work for different flow controls?
//
//
//  For an if, set interpreter to ignore all til end of if?
//  For a while, set pointer to return to at end of statement?
//  For a for, do the same as for while
//  For a switch, what do we do?
//
//  Now, what do we do with nested statements?  We have an array of 
//  pointer, which is added to when a flow is encountered, and
//  popped when a flow ends.
//
//  So... 
//    1) Recognize the flow
//    2) Evaluate the Condition
//    3) Set the evaluation flag based on condition
//    4) if flow is for, while
//      a) push return pointer to pointer array
//      b) Return pointer is back to line of condition
//    5) Execute until end of flow
//      a) dont execute if eval flag is 0
//    6) At end of flow, go back to pointer (popped from list)
//      a) Maybe if pointer is SSI_NULL, continue
//      b) if pointer is not null, go to the pointer for flow
//    7) If there is a pointer, perform the check
//
//  Now everything can completely occur from Evaluate
//  You dont have to worry about brace counters since each pointer
//  gets popped when a close brace is found.
//  If end of script is found, and there are still braces, error out.
//
//  NEED A SET_PTR FOR CINPUT
//  ALSO NEED TO CONVERT CCONSOLE TO USE SCRIPTLINES
//
//  Functions will be treated as new CScripts (maybe a subclass of)
//  


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CInterpreter::CInterpreter(CInput* In)
{
	// Ensure embedded variables are registered before use (else cannot use in function declarations)
	CDataInt anInt;
	CDataReal aReal;
	CDataBool aBool;
	CDataString aString;
	CDataVoid aVoid;
	CDataException anException;


  COMMENT_INDICATOR = "#";
  ESCAPE_INDICATOR = "\\";
  BEGIN_STRING = "\"";
  END_STRING = "\"";

  Engine = SSI_NULL;
  LastFlow = SSI_NULL;

  String s = "(";
  StartBrackList.push(s);
  s = "[";
  StartBrackList.push(s);
  s = ")";
  StopBrackList.push(s);
  s = "]";
  StopBrackList.push(s);

  Input = In;
  //BCtr = 0;
  gInitialized = 0;
  bFunctionReturnState = 0;
	bStopFlag = 0;

	StatementList = new CScriptStatementList;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

CInterpreter::~CInterpreter()
{
	if(StatementList){
		delete StatementList;
	}
  //SetLastFlow(0);
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

SSI_BOOL CInterpreter::Interpret(const String& Line, ScriptNode* InNode)
{
  CVariable Var;
  CStatus aStat;
	CScriptLine aLine;
  SSI_BOOL Ret = 0;
  SSI_INT64 LineNum = 0;
  String sLineNum;
	SSI_INT64 startind = 0;
	SSI_INT64 endind = 0;
	SSI_INT64 stat_ctr;
	ScriptStatementNode* sNode;
	CScriptStatement aStatement;

	//TNode2<int> aList;


  if(Line.GetLength() <= 0) return 1;

		if(InNode){
			startind = StatementList->GetCurrIndex();
			InNode->Get(aLine);

			SeparateToStatements(aLine, *StatementList);
			endind = StatementList->GetCurrIndex();

			for(stat_ctr = startind+1; stat_ctr <= endind; stat_ctr++){
				sNode = StatementList->GetByIndex(stat_ctr);//Statements[stat_ctr];
				sNode->Get(aStatement);
				String sLine = aStatement.Statement;

				if(aStat = Evaluate(sLine, Var))
				{
					if(GetReturnState() || GetStopState()){
						if(GetStopState()){
							sNode = StatementList->GetCurrentStatement();
							sNode->Get(aStatement);
							ScriptNode* aNode = Input->GetByID(aStatement.LineID);
							if(aNode){
								aNode->Get(aLine);
								LineNum = aLine.LineNum;
								sLineNum.Format("%d", LineNum);
							}else{
								sLineNum = "??";
							}
							Ret = DisplayMessage(sLineNum, String("Exited..."));
						}
						return 1;
					}
					// Do this for flow control stuff
					stat_ctr = StatementList->GetCurrIndex();
					endind = StatementList->IndexOf(StatementList->GetLastStatement());
					if(stat_ctr < 0){
						stat_ctr = endind + 1;  // force a break out, so it needs to get the rest of the lines
					}
					//return 1;
				}
				else
				{
					//  ERROR RETURNS REALLY SCREW THINGS UP!!  LIKE CHECK THE LINE NUMBER OF FOLLOWING ERRORS (especially with loops)!!!
					sNode = StatementList->GetCurrentStatement();
					sNode->Get(aStatement);
					
					ScriptNode* aNode = Input->GetByID(aStatement.LineID);
					if(!aNode){
						LineNum = -1;
						sLineNum = "??";					
					}else{
						aNode->Get(aLine);
						LineNum = aLine.LineNum;
						sLineNum.Format("%d", LineNum);
					}

					// Go to the end
					StatementList->SetCurrIndex(-1);

					Ret = DisplayError(aStat, sLineNum);
					return Ret;
				}
			}
		}else{
      
      // This does not work either, as it ultimately checks the input script list
      //CScriptStatementList newList;
      //CScriptStatementList* oldList = StatementList;
      //CScriptLine aLine;
      //aLine.Line = Line;
      //aLine.LineNum = -1;
      //SeparateToStatements(aLine, newList);
      //StatementList = &newList;
			if(aStat = Evaluate(Line, Var))  // This will never succeed as is
			{
        //StatementList = oldList;
				return 1;
			}else{
        //StatementList = oldList;
        String LineMessage = "{Line Entry: ";
        LineMessage = LineMessage + Line;
        LineMessage = LineMessage + "}";
        Ret = DisplayError(aStat, LineMessage);
				return Ret;
			}
		}
		return 1;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

SSI_BOOL CInterpreter::DeComment(String& In)
{
  SSI_INT64 Pos = In.Find(COMMENT_INDICATOR);
  if(Pos >= 0)
  {
    In = In.Left(Pos);
    return 1;
  }
  return 0;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

void CInterpreter::SetEngine(CEngine *Eng)
{
  Engine = Eng;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

CStatus CInterpreter::CheckNewVariable(ComponentItor Itor, CComponentParser& aParser, CVariable& NewVar)
{
  String Word;
	String Name;
	CStatus Ret;

	SSI_INT64 Type = 0;
	ScriptComponentT C; 
	ComponentItor Start;
	ComponentItor End;
	ComponentItor Temp;

	if(Itor == aParser.end()){
		return STAT_ERR;  // Internal Error (Dev?) KEEP
	}
	
  C = *Itor;
	
	Word = C.Component;
  Word.Trim();
	if(Type = GetVariableType(Word)){
		Start = Itor;
		Itor = aParser.GetNextNode(Itor);


		
	#ifdef USE_MY_LISTS
    while(Itor.next() != SSI_NULL){
  #else  
    while(Itor != aParser.end()){        
  #endif
      C = *Itor;

			if(C.Component.IsWhiteSpace() && (C.Type == COMPONENT_TOKEN)){
				Itor = aParser.GetNextNode(Itor);
			}else{
				if(C.Type == COMPONENT_STATEMENT){
					Name = C.Component;
		      Ret = Engine->AddNewVariable(Type, Name, String(""));
			    if(!Ret) return Ret;

				  NewVar.Name = Name;
				  NewVar.SetType(Type);
					if(!Engine->GetVariable(NewVar)) return CStatus(sERROR, ERR02019);
  
					Temp = aParser.prev(Start); //ssi_prevStart - 1;
					End = Itor;
					aParser.DeleteNodeRange(Start, End);
					
					C.Type = COMPONENT_VARIABLE;
					C.Vars.clear();
					C.Vars.push_back(NewVar);
					aParser.InsertAfter(Temp, C);

					return STAT_SUCCESS;
				}else{
					// must be followed by a statement
					MAKEERR1(ERR03301, Word.Str());
				}
			}
		}
		// Never found an acceptable statement (ie, no variable name)
		MAKEERR1(ERR03302, Word.Str());
	}else{
		return STAT_OK;
	}
}







// This needs to copy the Line
// --eff-- Look at this to make more efficient
CStatus CInterpreter::CheckNewVariable(String Line, CVariable& NewVar)
{
  CStatus Ret;
  String Word;
  String Name;
  String Value;
  String sTemp;
  SSI_INT64 Type = 0;

  Line.SetQuoteState(1);
  
  Line.Trim();
  if(Line.Parse(" ", Word) > 0)
  {
    Word.Trim();
    if(Type = GetVariableType(Word))
    {
      sTemp = Line;
      if(Line.Parse("=", Word) > 0)
      {
        Name = Word;
        Ret = Engine->AddNewVariable(Type, Name, Value);
        if(!Ret) return Ret;

        CVariable Temp;
        Line = sTemp;
        Ret = Evaluate(Line, Temp);
        if(!Ret) return Ret;
      }
      else
      {
        Name = Line;
        Name.Trim();
        Ret = Engine->AddNewVariable(Type, Name, Value);
        if(!Ret) return Ret;
      }
    }
    else
    {
      return STAT_OK;
    }
  }
  else
  {
    return STAT_OK;
  }
  NewVar.Name = Name;
  NewVar.SetType(Type);
  if(!Engine->GetVariable(NewVar)) return CStatus(sERROR, ERR02019);
  return STAT_SUCCESS;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

SSI_INT64 CInterpreter::GetVariableType(const String& In)
{
  CData* aData = Factory_MakeData(In.Str());
	if(aData){
		SSI_INT64 Ret = aData->Type;
		delete aData;
		return Ret;
	}
	return 0;
	//if(In == "string") return dSTRING;
  //if(In == "int") return dINT;
  //if(In == "real") return dREAL;
  //if(In == "ssi_BOOL") return dBOOL;
  //return 0;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

String CInterpreter::GetVariableString(SSI_INT64 In)
{
	CData* aData = Factory_MakeData(In);
	if(aData){
		String Ret = aData->DataName;
		delete aData;
		return Ret;
	}
	return "Data type not found";

  //if(In == dSTRING) return "string";
  //if(In == dINT) return "int";
  //if(In == dREAL) return "real";
  //if(In == dBOOL) return "ssi_BOOL";
  //return "void";
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

/*
CStatus CInterpreter::EvaluateLevel(SSI_INT64 Level, const String& Input, String& RetString, CVariable &RetVar){
	
	// How about this...
	//  Separate into tokens and variables
	//  anything that is not alnum is a token
	//  all else are variables
	// What do we do about parens, and '.'s?



	if(Input.GetLength() <= 0) return STAT_OK;
	
	CStatus RetStat;

	String Left;
	String Right = Input;
	String Tok;
	String Toks;
	String ReturnedString;
	String Ret;
	SSI_INT64 Pos;

	CStatement aStat;
	aStat.Interp = this;
	aStat.Engine = Engine;

	CVariable LeftVar;
	CVariable RightVar;
	CVariable NewVar;

	COperator anOp;

	if(Level == 1){
		while((Pos = Right.Parse(String("="), Left, &Tok)) >= 0){
			RetStat = EvaluateLevel(Level+1, Left, ReturnedString, LeftVar);
			if(!RetStat) return RetStat;
			RetStat = EvaluateLevel(Level, Right, ReturnedString, RightVar);
			if(!RetStat) return RetStat;
			if(LeftVar.GetType()){
				aStat.Type = S_OPERATOR;
				anOp.SetRight(RightVar);
				anOp.SetLeft(LeftVar);
				anOp.Type = COperator::StrToType(Tok);
				aStat.anOperator = anOp;

				RetStat = Engine->Evaluate(aStat);
				if(!RetStat) return RetStat;

				RetVar = aStat.RetVar;

				RetStat = Engine->SetVariable(aStat.RetVar);
				if(!RetStat) return RetStat;    
			}else{
				return STAT_ERR;
			}
			Right = ReturnedString;
		}
		if(Right.GetLength() <= 0){
			return STAT_OK;
		}else{
			RetStat = EvaluateLevel(Level+1, Right, ReturnedString, RightVar);
			RetVar = RightVar;
			return RetStat;
		}
	}else if(Level == 2){
		while((Pos = Right.Parse(String("+-"), Left, &Tok)) >= 0){
			RetStat = EvaluateLevel(Level+1, Left, ReturnedString, LeftVar);
			if(!RetStat) return RetStat;

			if(LeftVar.GetType()){
				RetStat = EvaluateLevel(Level, Right, ReturnedString, RightVar);
				if(!RetStat) return RetStat;

				aStat.Type = S_OPERATOR;
				anOp.SetRight(RightVar);
				anOp.SetLeft(LeftVar);
				anOp.Type = COperator::StrToType(Tok);
				aStat.anOperator = anOp;

				RetStat = Engine->Evaluate(aStat);
				if(!RetStat) return RetStat;

				RetVar = aStat.RetVar;
			}else{
				if(Tok == "-"){
					
					// Do we parse out everything until the first non-
					// alpha-numeric character?

					// Need to get the rightvar...
					//RightVar.GetWorkingData().negate();
					//RetVar = RightVar;
				}else{
					// Hanging '+'
					return STAT_ERR;
				}
			}

			
			//if(LeftVar.GetType()){
			//}else{
			//}
			Right = ReturnedString;
		}
		if(Right.GetLength() > 0){
			RetStat = EvaluateLevel(Level+1, Right, ReturnedString, RightVar);
			RetVar = RightVar;
			return RetStat;
		}else{
			return STAT_OK;
		}
	}else if(Level == 3){
		String sTemp = Input;
		sTemp.Trim();

	  if(!(RetStat = EvaluateKeyword(sTemp))) return RetStat;
	  if(RetStat == STAT_SUCCESS) return RetStat;

		CFlowStruct aFlow;
		aFlow.bCond = 1;
		while((RetStat = EvaluateFlow(sTemp, aFlow)) == STAT_SUCCESS)
		{
		  if(RetStat == STAT_SUCCESS){
				RetStat = ProcessFlow(sTemp, aFlow);
				if(!RetStat) return RetStat;
				ScriptStatementNode* aNode;
				CScriptStatement aStat;
				aNode = GetNextStatement(aStat);
				if(!aNode) return STAT_OK;
				sTemp = aStat.Statement;

				////////////////////////////////////
				DeComment(sTemp);
				sTemp.Trim();
				if(sTemp == FLOW_CLOSE_BRACE){
					// Fix those darn end statements
					return STAT_OK;
				}
			}
		}

		ChopEnder(sTemp);
		sTemp.Trim();

		// This handles functions
		Toks = "()";
		Pos = sTemp.Parse(Toks, Ret, &Tok);
		if(Tok == "(")
		{
			CFunctionDecl aDecl;
			aDecl.Name = Ret;
			if(Engine->FindFunctionDecl(aDecl)){
				return EvaluateFunction(sTemp, Ret, RetVar);
			}
		}

		SSI_INT64 Type;
		// This avoids accidental operator processing
		// Perhaps move all variable ops here?
		if(Type = CVariable::TypeFromString(sTemp)){
			//  Restore this
			CVariable Var;
			Var.SetType(Type);
			Var.Name = "";
			Var.SetWorkingNode(SSI_NULL);

			// The memory leak is here!!!!!!!
			if(!(RetStat = Var.SetData(sTemp, SSI_NULL))) return RetStat;
			RetVar = Var;
			return STAT_SUCCESS;
		}

		sTemp = Input;
		ChopEnder(sTemp);
		sTemp.Trim();

		RetStat = CheckNewVariable(sTemp, NewVar);
		if(!(RetStat)) return RetStat;
		if(RetStat == STAT_SUCCESS){
			RetVar = NewVar;
			return RetStat;
		}
		

		sTemp = Input;
		ChopEnder(sTemp);
		sTemp.Trim();

		// Get a Variable
		CVariable Var;
		SSI_INT64 Index = 0;

		String Original = sTemp;
      
		VarTree ClassVar;

		Var.Name = sTemp;
		Var.SetType(dUNKNOWN);
		aStat.RetVar = Var;
		aStat.Type = S_GETVAR;
		aStat.Interp = this;
		aStat.Engine = Engine;
	
		if(IsClass(sTemp)){
			RetStat = DoClass(sTemp, Var, ClassVar);
			if(!RetStat) return RetStat;

			// This is simply to get the variable...
			RetVar = Var;
			return RetStat;
		}
		sTemp = Original;  // Class schtuff

		if(Engine->Evaluate(aStat))
		{
			// How to pass on Node information here??
			Var = aStat.RetVar;
			RetVar = Var;
			return STAT_SUCCESS;
		}else{
			MAKEERR1(ERR02017, sTemp.Str());
		}
	}

	return STAT_ERR;
}
*/

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////


// --eff-- make more efficient
CStatus CInterpreter::Evaluate(const String& inLine, CVariable &RetVar)
{
	CStatus RetStat;
	String sTemp = inLine;
	/*
	while(1){
		 SSI_INT64 Pos = sTemp.Find(COMMENT_INDICATOR);
		// if(Pos >= 0){
		//	In = In.Left(Pos);
		//	return 1;
		// }
		//return 0;

		//if(RetStat == STAT_OK){
		//}
		//sTemp.SetQuoteState(1);
		//sTemp = inLine;
		DeComment(sTemp);
	}
	*/
// Uncomment...


	sTemp.SetQuoteState(1);
	DeComment(sTemp);
	
	sTemp.Trim();
	if(sTemp.GetLength() <= 0){
		return STAT_OK;
	}

	if(QueryInput() == 0){
		SetStopFlag();
		return STAT_OK;
	}

	//////////////////////////////////////////////////////////////////////////////////////////
	// Special Statements (non-parsed)

  // ---- Keyword Check -----------------------------------------

// Uncomment...
  if(!(RetStat = EvaluateKeyword(sTemp))) return RetStat;
  if(RetStat == STAT_SUCCESS) return RetStat;

  // ---- Flow Check -----------------------------------------
	CFlowStruct aFlow;
	aFlow.bCond = 1;
	SSI_BOOL bDoFlow = 0;
  SSI_BOOL bCatchOK = 0;
	if((RetStat = EvaluateFlow(sTemp, aFlow)) == STAT_SUCCESS){
		bDoFlow = 1;
	}

	while(bDoFlow){


    if(RetStat == STAT_SUCCESS){

      // OK, I think this is needed for the variables
      // declared within the conditionals... then
      // need one for each loop of the processor
      // Try creates global variables

      CEngine* anEng = 0;
      CEngine* oldEng = 0;
      if(aFlow.Type != COND_TRY){
        anEng = Engine->CreateFunctionEngine();
        anEng->SetLoopEngine();
        oldEng = Engine;
        Engine = anEng;
      }

			RetStat = ProcessFlow(sTemp, aFlow);

      // Try creates global variables
      if(aFlow.Type != COND_TRY){
        
        if(oldEng){
          Engine = oldEng;
        }

        if(anEng){
          delete anEng;
          anEng = 0;
        }
      }

      if(aFlow.Type == COND_CATCH && bCatchOK == 0){
        
        // catch must follow a try
        MAKEERR0(ERR03386)
      }
      if(aFlow.Type == COND_TRY){
        bCatchOK = 1;
      }else{
        bCatchOK = 0;
      }
      if(!RetStat){
        if(aFlow.Type == COND_TRY){
          aFlow.Exception.SetStatus(RetStat);
        }else{
          return RetStat;
        }
      }

			if(GetReturnState() || GetStopState()){
				return STAT_OK;
			}

			ScriptStatementNode* aNode;
			CScriptStatement aStat;
			aNode = GetNextStatement(aStat);
      if(!aNode){
        return STAT_OK;
      }
			sTemp = aStat.Statement;

			////////////////////////////////////
			DeComment(sTemp);
			sTemp.Trim();

			// This should handle elses, etc...

      // Need to make sure a catch and else cannot be by itself
			bDoFlow = 0;
      if(aFlow.Type == COND_TRY){
        if((RetStat = EvaluateFlow(sTemp, aFlow)) == STAT_SUCCESS){
          if(aFlow.Type != COND_CATCH){
            MAKEERR0(ERR03383)
          }else{
            bCatchOK = 1;
            bDoFlow = 1;
          }
        }else if(RetStat){
          MAKEERR0(ERR03384)
          // ERROR TRY MUST BE FOLLOWED BY CATCH
        }else{
          return RetStat;  // An error already occurred
        }
      }else if((RetStat = EvaluateFlow(sTemp, aFlow)) == STAT_SUCCESS){
        if(aFlow.Type == COND_CATCH){
            MAKEERR0(ERR03385)
        }
				bDoFlow = 1;
			}else if(sTemp.GetLength() <= 0 || sTemp == FLOW_CLOSE_BRACE){ // If all it is is a close brace...
        return STAT_OK;
			}else{
				return Evaluate(sTemp, RetVar);
			}
    }
	}

	if(GetReturnState() || GetStopState()){
		return STAT_OK;
	}
	ChopEnder(sTemp);
	//////////////////////////////////////////////////////////////////////////////////////////
	// Parsed Statements

	CComponentParser aParser;
	aParser.ParseLine(sTemp);
	return Evaluate(aParser, RetVar);
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
CStatus CInterpreter::Evaluate(CComponentParser& aParser, CVariable& RetVar)
{
	CStatus RetStat;
	CStatement aStat;
	COperator anOp;

	String sTemp;

	ScriptComponentT aComponent;

	ComponentItor Itor = aParser.begin();  //aParser.GetTop();
  ComponentItor TempItor;
	ComponentItor StartItor;
	ComponentItor EndItor;

	SSI_INT64 bCTR = 0;

  // REMOVE THIS LATER, AND ITS INPUT INTO 3313 (why?)
  String sLine;
  Itor = aParser.begin();

  if(Itor == aParser.end()){
    return STAT_OK;  // No statements to process.   Fixes the double ; at end of line
  }

  #ifdef USE_MY_LISTS
  while(Itor != aParser.end()){
    C = *Itor;
    ScriptComponentT C;
    Itor->Get(C);
    sLine = sLine + C.Component;
    Itor = Itor->Next;
  #else
	while(Itor != aParser.end()){
    sLine = sLine + (*Itor).Component;
    Itor++;
  #endif
  }
  Itor = aParser.begin();

	//////////////////////////////////////////////////////////////////////////////////////////
	// FUNCTION SEARCHER
	while(Itor != aParser.end()){
#ifdef USE_MY_LISTS
    Itor->Get(aComponent);
#else
    aComponent = *Itor;
#endif
		
		if(aComponent.Type == COMPONENT_STATEMENT){
			ScriptComponentT aT;
			
			SSI_BOOL bCLASS_AT_LEFT = 0;
			CData* LeftClass = 0;
			
			if(Itor != aParser.begin()){
				TempItor = aParser.prev(Itor); //Itor - 1;
#ifdef USE_MY_LISTS
        TempItor->Get(aT);
#else
				aT = *TempItor;
#endif
				if((aT.Type == COMPONENT_VARIABLE) && (aComponent.Component[0] == '.')){

					// Get previous component, determine if it is a variable (thus a class)
					VarItor LeftItor = aT.Vars.begin();
					CVariable LeftVar;
					LeftVar = *LeftItor;

					// Chop off the '.'
					sTemp = aComponent.Component;
					sTemp.Reverse();
					sTemp.chop();
					sTemp.Reverse();

					// Use code from Statement eval to get LeftVar...
					LeftClass = (CData*)&LeftVar.GetWorkingData();
					
					// If this is a function member of the class, evaluate the class
					if(LeftClass->IsFunction(sTemp)){
						bCLASS_AT_LEFT = 1;
					}
				}
			}

			if(IsClassFunction(aComponent.Component) || Engine->IsFunction(aComponent.Component) || bCLASS_AT_LEFT){
        String FunctionName = aComponent.Component;
				StartItor = Itor;
				Itor = aParser.GetNextNode(Itor); //++Itor;  // = aParser.GetNextNode(aNode);
				if(Itor == aParser.end()){
					MAKEERR1(ERR03303, aComponent.Component.Str());
					// Function Mission Parameters
				}
#ifdef USE_MY_LISTS
        Itor->Get(aComponent);
#else
				aComponent = *Itor;
#endif
				if((aComponent.Type == COMPONENT_TOKEN) && (aComponent.Component == "(")){
					bCTR = 1;
					Itor = aParser.GetNextNode(Itor);//++Itor;
					while(Itor != aParser.end()){
#ifdef USE_MY_LISTS
            Itor->Get(aComponent);
#else
						aComponent = *Itor;
#endif
						if((aComponent.Type == COMPONENT_TOKEN) && (aComponent.Component == "(")){
							bCTR++;
						}else if((aComponent.Type == COMPONENT_TOKEN) && (aComponent.Component == ")")){
							bCTR--;
							if(bCTR <= 0){
								EndItor = Itor;
								break;
							}
						}
						Itor = aParser.GetNextNode(Itor);//++Itor;
					}
					if(bCTR){
						// No closing paren found
						MAKEERR1(ERR03304, FunctionName.Str());
					}
					// Perform function using nodes
					// For the time being, we will reconstruct the function				
#ifdef USE_MY_LISTS
          StartItor->Get(aComponent);
#else
					aComponent = *StartItor;
#endif
					String sTemp = "";
					CVariable aVar;
					String sFuncName = aComponent.Component;

					Itor = StartItor;
					Itor = aParser.next(Itor);//++Itor;
					while(Itor != aParser.next(EndItor)){
						sTemp = sTemp + (*Itor).Component;
						Itor = aParser.GetNextNode(Itor);//++Itor;
					}

					// this handles cases where component begins with a dot operator, and the left is a variable
					if(bCLASS_AT_LEFT){

						// Must do this, because want to replace left var *and* this component
						StartItor = aParser.prev(StartItor);//--StartItor;

						// Get rid of the beginning dot
						sFuncName.Reverse();
						sFuncName.chop();
						sFuncName.Reverse();

						// Construct the statement... this is similar to EvaluateFunction
						CFunction theFunc;
						aStat.Type = S_FUNCTION;
						aStat.Interp = this;
						aStat.Engine = Engine;

						RetStat = BuildFunction(sTemp, theFunc);
						if(!RetStat)return RetStat;

						theFunc.Name = sFuncName;
						aStat.aFunction = theFunc;

						if(!(RetStat = LeftClass->EvalFunction(aT.Vars.begin(), aT.Vars, aStat))) return RetStat;
						aVar.CopyVariable(aStat.aFunction.GetReturn());
					}else{
						RetStat = EvaluateFunction(sTemp, sFuncName, aVar);
						if(!RetStat) return RetStat;
					}

					TempItor = aParser.prev(StartItor); //StartItor - 1;
					aParser.DeleteNodeRange(StartItor, EndItor);
					
          // Test CODE
          //String Q;
          //ComponentItor ItorL = aParser.begin();
          //while(ItorL != aParser.end()){
					//	Q = Q + (*ItorL).Component;
					//	ItorL = aParser.GetNextNode(ItorL);//++Itor;
					//}

					aComponent.Type = COMPONENT_VARIABLE;
					aComponent.Vars.clear();
					aComponent.Vars.push_back(aVar);

					aParser.InsertAfter(TempItor, aComponent);
					Itor = aParser.GetCurrItor();

				}else{
					// Function needs parameter list
					// consider typecasts (eg string(i))
					// return STAT_ERR;
				}
			}
		}
		Itor = aParser.GetNextNode(Itor);//++Itor;
	}

  //////////////////////////////////////////////////////////////////////////////////////////
	// INSERT PARENS HERE
	Itor = aParser.begin();
	while(Itor != aParser.end()){
		aComponent = *Itor;
		if((aComponent.Type == COMPONENT_TOKEN) && (aComponent.Component == "(")){

      // Check if immediate left is a statement... if so,
      // then a bad function?
      StartItor = aParser.prev(Itor);
      //if(Itor){
        if(StartItor != aParser.end()){
          aComponent = *StartItor;
          if(aComponent.Type == COMPONENT_STATEMENT){
            MAKEERR1(ERR03338, aComponent.Component.Str());
          }
        }
      //}

			StartItor = Itor;
			bCTR = 1;
			Itor = aParser.GetNextNode(Itor);//++Itor;  // = aParser.GetNextNode(aNode);
			while(Itor != aParser.end()){
				aComponent = *Itor;
				if((aComponent.Type == COMPONENT_TOKEN) && (aComponent.Component == "(")){
					bCTR++;
				}else if((aComponent.Type == COMPONENT_TOKEN) && (aComponent.Component == ")")){
					bCTR--;
					if(bCTR <= 0){
						EndItor = Itor;
						break;
					}
				}
				Itor = aParser.GetNextNode(Itor);//++Itor;
			}
			if(bCTR){
				// No closing paren found
				MAKEERR0(ERR03305);
			}

			// For the time being, we will reconstruct the paren statement
			String sTemp = "";
			CVariable aVar;
			Itor = StartItor;
			Itor = aParser.next(Itor);//++Itor;
			//aNode = aNode->next(); // Skip paren
			
      // OLD CODE, DOESNT WORK BECAUSE IF NESTED PARENS WITH
      // FUNCTION CALL, FUNCTION CALL RESULT (WITH FUNCTION'S NAME)
      // WILL BE INSERTED AND WILL HAVE NO PARAMETERS
      // TRY if((int i = StrToInt("10")) > 0){ FOR EXAMPLE
      //while(Itor != EndItor){
			//	sTemp = sTemp + (*Itor).Component;
			//	Itor = aParser.GetNextNode(Itor);//++Itor;
			//}
      CComponentParser TempParser;
      while(Itor != EndItor){
        TempParser.push((*Itor));
        Itor = aParser.GetNextNode(Itor);
      }
      
      RetStat = Evaluate(TempParser, aVar);
			//RetStat = Evaluate(sTemp, aVar);
			if(!RetStat) return RetStat;

			TempItor = aParser.prev(StartItor); //StartItor - 1;
			aParser.DeleteNodeRange(StartItor, EndItor);
					
			aComponent.Type = COMPONENT_VARIABLE;
			aComponent.Vars.clear();
			aComponent.Vars.push_back(aVar);
			aParser.InsertAfter(TempItor, aComponent);
			Itor = aParser.GetCurrItor();

		}
		Itor = aParser.GetNextNode(Itor);//++Itor;
      }


	//////////////////////////////////////////////////////////////////////////////////////////
	// STATEMENT SEARCHER

	Itor = aParser.begin();
	while(Itor != aParser.end()){
		aComponent = *Itor;
		if(aComponent.Type == COMPONENT_STATEMENT){

			CVariable aVar;
			CVariable Var;

			VarTree aTree;

			SSI_INT64 Index = 0;
			SSI_INT64 Type;

			String sTemp = aComponent.Component;
			String Original = sTemp;

			ChopEnder(sTemp);
			sTemp.Trim();

			if(Type = CVariable::TypeFromString(sTemp)){
				//  Restore this
				Var.SetType(Type);
				Var.Name = "";
				Var.SetWorkingNode(SSI_NULL);

				if(!(RetStat = Var.SetData(sTemp, SSI_NULL))) return RetStat;
				aTree.clear();
				aTree.push_back(Var);
			  aComponent.Type = COMPONENT_VARIABLE;
				aComponent.Vars = aTree;

				StartItor = Itor;
				EndItor = Itor;
				TempItor = aParser.prev(StartItor); //StartItor - 1;
                aParser.DeleteNodeRange(StartItor, EndItor);

				aParser.InsertAfter(TempItor, aComponent);

				Itor = aParser.GetCurrItor();
			}else{
				// This will inject the new variable  --> OK
				RetStat = CheckNewVariable(Itor, aParser, Var);
				if(!(RetStat)) return RetStat;
				if(RetStat == STAT_SUCCESS){
					Itor = aParser.GetCurrItor();
					
					// If this is not true, it is because this is now the first statement in the list
					if(Itor != aParser.begin()){
						Itor = aParser.prev(Itor);
						//--Itor;
					}
					// Else, we want to skip it later on...

				}else{
					String sTemp = aComponent.Component;
					ChopEnder(sTemp);
					
					ScriptComponentT aT;

					// this is where we check to see if first token of component is '.'
					if(sTemp.Find(CLASS_EVAL_SEPARATOR) == 0){

						// Get previous component, determine if it is a variable (thus a class)
						// TempNode = aNode->prev();
						if(Itor != aParser.begin()){
							TempItor = aParser.prev(Itor);//--TempItor;
							aT = *TempItor;
							if(aT.Type == COMPONENT_VARIABLE){
								CVariable aVar;

								// Chop off the '.'
								sTemp.Reverse();
								sTemp.chop();
								sTemp.Reverse();

								// The variable is pushed in the DoClass section
								RetStat = DoClass(sTemp, aVar, aT.Vars);
								if(!RetStat) return RetStat;

								// Set the variable list
								*Itor = aT;

								// Replace the node set as usual
								StartItor = Itor;
								EndItor = Itor;
								TempItor = aParser.prev(StartItor); //StartItor - 1;
								aParser.DeleteNodeRange(StartItor, EndItor);
								Itor = aParser.GetCurrItor();

							}else{
								MAKEERR1(ERR03306, sTemp.Str());
							}
						}else{
							MAKEERR1(ERR03307, sTemp.Str());
						}
					}else{

						sTemp.Trim();

						// Get a Variable
						Var.Name = sTemp;
						Var.SetType(dUNKNOWN);
						aStat.RetVar = Var;
						aStat.Type = S_GETVAR;
						aStat.Interp = this;
						aStat.Engine = Engine;
	
						if(IsClass(sTemp)){
							RetStat = DoClass(sTemp, Var, aTree);
							if(!RetStat) return RetStat;

							aTree.push_back(Var);
						}else{
							sTemp = Original;  // Class schtuff

							if(RetStat = Engine->Evaluate(aStat)){
								// How to pass on Node information here??
								aTree.clear();
								aTree.push_back(aStat.RetVar);
							}else{
								return RetStat;
							}
						}

						StartItor = Itor;
						EndItor = Itor;
						TempItor = aParser.prev(StartItor); //StartItor - 1;
						aParser.DeleteNodeRange(StartItor, EndItor);

						aComponent.Type = COMPONENT_VARIABLE;
						aComponent.Vars.clear();
						aComponent.Vars = aTree;
						aParser.InsertAfter(TempItor, aComponent);
						Itor = aParser.GetCurrItor();
					}
				} // If start is '.'
			}  // Type from string
		}
		Itor = aParser.GetNextNode(Itor);//++Itor;

	}

	//////////////////////////////////////////////////////////////////////////////////////////
	// SPECIAL OPERATOR SEARCHER

	String Ops = "-+!";
	CVariable aVar;

	Itor = aParser.begin();
	while(Itor != aParser.end()){
		SSI_BOOL bNEGATE = 0;
    SSI_BOOL bNOT = 0;
		SSI_BOOL bDidToken = 0;
		aComponent = *Itor;
		if(aComponent.Type == COMPONENT_TOKEN){
			if(aComponent.Component.FindOneOf(Ops) == 0){
        if(aComponent.Component == OPERATOR_NOT){
          bNOT = 1;
        }
			    StartItor = aParser.GetLeft(Itor);
			    EndItor = aParser.GetRight(Itor);
			    if((EndItor == aParser.next(Itor)) && (EndItor != aParser.end())){
			      aComponent = *EndItor;
					  if(aComponent.Type == COMPONENT_VARIABLE){
					    if(!aComponent.pop(aVar)){
					    	return STAT_ERR;   // KEEP
					    }
						  if(StartItor != aParser.end()){
							  aComponent = *StartItor;
							  if(aComponent.Type == COMPONENT_TOKEN){
								  bNEGATE = 1;
							  }else{
								  bNEGATE = 0;
								  // Consider the case int i = 10 -1;
								  //return STAT_ERR;
							  }
						  }else{
							  bNEGATE = 1;
						  }
	  				}else{
						StartItor = aParser.prev(Itor);
						EndItor = aParser.next(Itor);
						aComponent = *Itor;					
						if(EndItor != aParser.end()){
							String CurrTok = aComponent.Component;
							aComponent = *EndItor;
							if((aComponent.Type == COMPONENT_TOKEN) && (aComponent.Component == CurrTok)){
                if(bNOT){
                  //#define ERR03337  "Consecutive '%s' operators illegal. (3337)"
                  MAKEERR1(ERR03337, OPERATOR_NOT);
                }
								// Try to get a variable on LHS
							  // If yes, op the variable, then set it to component
							  if(StartItor != aParser.end()){
							  	aComponent = *StartItor;
								if(aComponent.Type == COMPONENT_VARIABLE){
									bDidToken = 1;
                  aComponent.pop(aVar);
									// If LHS, push back on before op
									aComponent.Vars.push_back(aVar);
									anOp.Left_Var = aVar;									

									if(COperator::StrToType(CurrTok) == oPLUS){
										anOp.Type = oINCREMENT;
									}else{
										anOp.Type = oDECREMENT;
									}

									aStat.Type = S_OPERATOR;
									aStat.anOperator = anOp;
									RetStat = Engine->Evaluate(aStat);
									if(!RetStat) return RetStat;
										
									aVar = aStat.RetVar;
								 }
                }
								// If no, check RHS
							  // Doh... If yes, set it to component, then op the variable
								if(!bDidToken && ((aParser.next(EndItor)) != aParser.end())){ // There wasnt a variable on LHS
									StartItor = Itor;
									EndItor = aParser.next(EndItor);//++EndItor;
									aComponent = *EndItor;
									if(aComponent.Type == COMPONENT_VARIABLE){
										bDidToken = 1;
 					                    aComponent.pop(aVar);
										anOp.Left_Var = aVar;									

										if(COperator::StrToType(CurrTok) == oPLUS){
											anOp.Type = oINCREMENT;
										}else{
											anOp.Type = oDECREMENT;
										}

										aStat.Type = S_OPERATOR;
										aStat.anOperator = anOp;
										RetStat = Engine->Evaluate(aStat);
										if(!RetStat) return RetStat;
										
										aVar = aStat.RetVar;
										// If RHS, push back on after op
										aComponent.Vars.push_back(aVar);
									}
								}
							}
						}
					}

					// This occurs if:
					//  Left == Token || Left = 0
					//  Right == Variable && Right = aNode->Next
					if(bNEGATE){
						CVariable bVar;  // For some reason, we have to copy the data
            if(bNOT){
              bVar.SetType(CDataBool::GetRegisteredType());
              CDataBool aBool;
              // Remember, it is a NOT
              if(aVar.GetWorkingData().boolean()){
                aBool.Data = 0;
              }else{
                aBool.Data = 1;
              }
              RetStat = bVar.SetWorkingData(&aBool);
              if(!RetStat) return RetStat;
            }else{
						  bVar.SetType(aVar.GetType()); //= aVar;
						  bVar.SetWorkingData(&aVar.GetWorkingData());
						  RetStat = bVar.GetWorkingData().negate();	
              if(!RetStat) return RetStat;
            }

						TempItor = aParser.prev(Itor);//Itor - 1;
						aParser.DeleteNodeRange(Itor, EndItor);
		  			aComponent.Type = COMPONENT_VARIABLE;
						aComponent.Vars.clear();
						aComponent.Vars.push_back(bVar);
						aParser.InsertAfter(TempItor, aComponent);
						Itor = aParser.GetCurrItor();
					}else if(bDidToken){
						// Incremented or decremented
						TempItor = aParser.prev(StartItor);//StartItor - 1;
						aParser.DeleteNodeRange(StartItor, EndItor);
	  				
		  			aComponent.Type = COMPONENT_VARIABLE;

						if(aComponent.Vars.size() > 1){  // If Multiple Variables
							RetStat = Engine->SetVariable(aComponent.Vars, aStat.RetVar);
						}else{
							RetStat = Engine->SetVariable(aStat.RetVar);
						}
						if(!RetStat) return RetStat;
						aParser.InsertAfter(TempItor, aComponent);
						Itor = aParser.GetCurrItor();
					}
				}
			}
		}
		Itor = aParser.GetNextNode(Itor);//++Itor;
	}

	//////////////////////////////////////////////////////////////////////////////////////////
	// OPERATOR SEARCHER

	SSI_INT64 OpLevel = 1;
	CVariable vLeft;
	CVariable vRight;
	VarTree aTree;

	while(OpLevel <= 6){
		if(OpLevel == 1){
      Ops = OPERATOR_LEVEL1; //"^";
    }else if(OpLevel == 2){
			Ops = OPERATOR_LEVEL2; //"*/";
		}else if(OpLevel == 3){
			Ops = OPERATOR_LEVEL3; //"+-";
		}else if(OpLevel == 4){
			Ops = OPERATOR_LEVEL4; //"<>!";  
		}else if(OpLevel == 5){
      Ops = OPERATOR_LEVEL5; //"&|";
    }else if(OpLevel == 6){
      Ops = OPERATOR_LEVEL6; //"="  // this should be OK here...
    }


		Itor = aParser.begin();
		while(Itor != aParser.end()){
			aComponent = *Itor;
			if(aComponent.Type == COMPONENT_TOKEN){
				// Change to oplevel later
				if(aComponent.Component.FindOneOf(Ops) == 0){
					// If this is negate operator, negate if variable on right and non-space token on left
					// If this is increment operator, increment if variable on right *or* left, and space on opposite
					// If this is decrement operator, decrement if variable on right *or* left, and space on opposite

					// Else, if this is regular op, perform op
					anOp.Type = COperator::StrToType(aComponent.Component);
   
          StartItor = aParser.GetLeft(Itor);
          EndItor = aParser.GetRight(Itor);
	
					// Check if next component is another operator...
					ComponentItor NextItor = aParser.next(Itor); //Itor+1;  //aNode->next();
					ScriptComponentT NextC;
					if(NextItor == aParser.end()){
						MAKEERR1(ERR03308, aComponent.Component.Str());
					}
					NextC = *NextItor;
					if(NextC.Type == COMPONENT_TOKEN){
						SSI_INT64 c = COperator::StrToType(NextC.Component);
						if(c){  // Could be a space
							RetStat = anOp.AddType(c);
							if(!RetStat) return RetStat;
							StartItor = aParser.GetLeft(Itor);  //Itor - 1;
							EndItor = aParser.GetRight(NextItor); //Itor + 1;
						}
					}

					// Requires a variable on left and right
					if(StartItor == aParser.end()){
						MAKEERR1(ERR03309, (COperator::TypeToStr(anOp.Type)).Str());
					}
					if(EndItor == aParser.end()){
						MAKEERR1(ERR03310, (COperator::TypeToStr(anOp.Type)).Str());
					}

					SSI_BOOL bLEFT_CLASS = 0;

					aComponent = *StartItor;
					if(aComponent.Type != COMPONENT_VARIABLE){
						// Requires variable
						
						MAKEERR1(ERR03311, (COperator::TypeToStr(anOp.Type)).Str());
					}else{
					    if(!aComponent.pop(vLeft)){
					    	return STAT_ERR;  // KEEP
					    }
					    if(aComponent.pop(aVar)){
							bLEFT_CLASS = 1;
							aComponent.Vars.push_back(aVar);
							aTree = aComponent.Vars;
    					}
					}
				
					aComponent = *EndItor;
					if(aComponent.Type != COMPONENT_VARIABLE){
						// Requires variable
						MAKEERR1(ERR03312, (COperator::TypeToStr(anOp.Type)).Str());
					}else{
					    if(!aComponent.pop(vRight)){
      						return STAT_ERR;  // KEEP
    					}					
					}

					aStat.Type = S_OPERATOR;
					anOp.SetRight(vRight);
					anOp.SetLeft(vLeft);
					aStat.anOperator = anOp;
					RetStat = Engine->Evaluate(aStat);
					if(!RetStat) return RetStat;
					aVar = aStat.RetVar;

					TempItor = aParser.prev(StartItor); //Itor - 1;
					aParser.DeleteNodeRange(StartItor, EndItor);
					aComponent.Type = COMPONENT_VARIABLE;
					aComponent.Vars.clear();
					aComponent.Vars.push_back(aVar);

					aParser.InsertAfter(TempItor, aComponent);

					Itor = aParser.GetCurrItor();

					// Equal Op....
					if(anOp.Type == oEQUAL){
						if(bLEFT_CLASS){
							RetStat = Engine->SetVariable(aTree, aStat.RetVar);
							if(!RetStat) return RetStat;
						}else{
							RetStat = Engine->SetVariable(aStat.RetVar);
							if(!RetStat) return RetStat;    
						}
					}
				}
			}
			Itor = aParser.GetNextNode(Itor);//++Itor;
		}
		OpLevel++;
	}

	SSI_INT64 FinalCnt = 0;
	Itor = aParser.begin();
	ComponentItor RetItor;
	while(Itor != aParser.end()){
		aComponent = *Itor;
		if(aComponent.Type == COMPONENT_VARIABLE){
			RetItor = Itor;
			FinalCnt++;
		}else if((aComponent.Type == COMPONENT_TOKEN) && (aComponent.Component.IsWhiteSpace())){
		}else{
			MAKEERR1(ERR03215, aComponent.Component.Str());  // Internal Error
		}
		Itor = aParser.GetNextNode(Itor);//++Itor;
		//aNode = aParser.GetNextNode(aNode);
	}

	// Should only have one variable component left
	if(FinalCnt != 1){

    sLine.Format("%s: %d", sLine.Str(), FinalCnt);
    //CScriptLine s;
    //GetCurrLine(s);
    MAKEERR1(ERR03313, sLine.Str());
	}

    aComponent = *RetItor;
    if(!aComponent.pop(RetVar)){
      return STAT_ERR;  // KEEP, I DONT KNOW WHY I WOULD GET HERE
    }

	return STAT_OK;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
CStatus CInterpreter::Parameterize(const String &Params, VarTree& Ret, String Toks)
{
	StringTree sTree;
	String sParam;
	StringNode* sNode;
	CStatus RetStat;

	CVariable aVar;

	String P = Params;
	P.SetQuoteState(1);

	RetStat = Parameterize(P, sTree, Toks);
	if(!RetStat) return RetStat;
	
	sNode = sTree.getTop();
	while(sNode){
		sNode->Get(sParam);
		RetStat = Evaluate(sParam, aVar);
		if(!RetStat) return RetStat;
		Ret.push_back(aVar);
		sNode = sNode->next();
	}
  return STAT_OK;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
// --eff-- make efficient
CStatus CInterpreter::Parameterize(const String &Params, StringTree& Ret, String Toks)
{
  String Temp = Params;
  String Param;
  SSI_INT64 Pos = 0;
  SSI_INT64 OPCtr = 0;

  Temp.SetQuoteState(1);  
  Ret.Clear();

  while((Pos = Temp.FindOneOf(Toks, Pos)) >= 0)
  {
    if(Temp[Pos] == '(')
    {
      OPCtr++;
      Pos++;
    }
    else if(Temp[Pos] == ')')
    {
      OPCtr--;
      Pos++;
      if(OPCtr < 0)
      {
        return CStatus(sERROR, ERR03002);
      }
    }
    else // This is for actual parameterize parameter (,; etc...)
    {
      if(OPCtr == 0)
      {
        Param = Temp.Left(Pos);
				Param.Trim();
        Temp = Temp.Right(Temp.GetLength() - Pos - 1);
        
        Temp.SetQuoteState(1);  
        Temp.Trim();
        Ret.push(Param);
        Pos = 0;
      }
      else
      {
        Pos++;
      }
    }
  }
	
  Temp.Trim();
  if(Temp.GetLength() > 0) // Prevent addition of a zero term
  {
		Ret.push(Temp);
  }

  if(OPCtr) return CStatus(sERROR, ERR03003);
  return STAT_OK;
}

/////////////////////////////////////////////////////////////////////
//  Function:    CInterpreter::EvaluateFunction
//  Scope:       Public
//  Parameters: 
//    String &Input:      The parameter list
//    String &sFuncName:  The name of the function to process (entire class path)
//    CVariable &RetVar:  Will contain the valid element found
//  Return:
//    CStatus:            The error status of the function
//  Modification History:
//    04/06/03:  Initial comments
//    04/07/04:  Recoded to handle all types of functions (class included)
//  Description:
//    Creates a statement type and sends it to the engine.  Retrieves
//    the parameters in parenthesis, and creates a parameter tree.
//    Evaluates each parameter before passing to a funcion.
//
/////////////////////////////////////////////////////////////////////
CStatus CInterpreter::EvaluateFunction(String& Input, String& sFuncName, CVariable& RetVar)
{


//		String Remainder;
//		String Params;
		CStatus RetStat;

//		VarTree pTree;
//		VarNode* pNode;

		CStatement aStat;
		CVariable aVar;
		VarTree ClassVar;

		CFunction theFunc;
		aStat.Type = S_FUNCTION;
		aStat.Interp = this;
		aStat.Engine = Engine;

      

		RetStat = BuildFunction(Input, theFunc);
		if(!RetStat)return RetStat;

//		if(!(RetStat = Parenthesize(Input, Params, Remainder))) return RetStat;
//		if(!(RetStat = Parameterize(Params, pTree))) return RetStat;

//		pNode = pTree.getTop();
//		while(pNode){
//			pNode->Get(aVar);
//			RetStat = theFunc.AddParam(aVar);
//			if(!RetStat) return RetStat;
//			pNode = pNode->next();
//		}

		// Add 'if is function' here first, to try to get a variable...
		// Or if in class... who knows?

		String sClass = sFuncName;

		if(IsClass(sClass)){
			// Extract the class name from the function
			String sDotOp = CLASS_EVAL_SEPARATOR;
			int ind = sFuncName.ReverseFind(sDotOp);
			if(ind >= 0){
				sClass = sFuncName.Left(ind);
				sFuncName = sFuncName.Right(sFuncName.GetLength() - ind - sDotOp.GetLength());
			}

			RetStat = DoClass(sClass, aVar, ClassVar);
			if(!RetStat) return RetStat;

			CData* aClass = (CData*)&aVar.GetWorkingData();
			theFunc.Name = sFuncName;
			aStat.aFunction = theFunc;

			// Add a CData::EvalFunction
			//  Will, in turn, call a virtual CData ProcessFunction

			//  Can get rid of getTop
			if(!(RetStat = aClass->EvalFunction(ClassVar.begin(), ClassVar, aStat))) return RetStat;
			RetVar.CopyVariable(aStat.aFunction.GetReturn());
		}else if(Engine->IsFunction(sFuncName)){

			theFunc.Name = sFuncName;
			aStat.aFunction = theFunc;
			if(!(RetStat = Engine->Evaluate(aStat))) return RetStat;
			if(!(RetStat = aStat.aFunction.GetStatus())) return RetStat;
			theFunc = aStat.aFunction;
			RetVar = theFunc.GetReturn();
		}else if(sFuncName.GetLength() > 0){
			// The function name is not found, or not available
			MAKEERR1(ERR01107, sFuncName.Str());
		}else{
			// Should never get here with new design
			return STAT_ERR;  // Internal Error  KEEP
			// This is here in case a random statement is in parens... (ie, i = (1+2);
      // String Right;
			// if(!(RetStat = Parenthesize(Input, Input, Right))) return RetStat;
      // if(!(RetStat = Evaluate(Input, aVar))) return RetStat;
      // RetVar = aVar;
    }
		return STAT_OK;
}

/////////////////////////////////////////////////////////////////////
//  Function:    CInterpreter::Parenthesize
//  Scope:       Public
//  Parameters: 
//    String In:        The string to parenthesize
//    String &Left:     Will contain everything before the last paren
//    String &Right:    Will contain everything after the last paren
//  Return:
//    CStatus:          The error status of the function
//  Modification History:
//    04/06/03:  Initial comments
//  Description:
//    Parenthesize takes a string and determines if a set of 
//    parenthesis are located.  If so, it returns as Left the
//    portion of the input before the last paren.  It returns as
//    Right everythung after the last paren.  It does this by 
//    counting the number of parens.  Returns an error if there 
//    are more opening parens than closing or vice-versa.  Returned
//    values do not include last paren.
//
/////////////////////////////////////////////////////////////////////
CStatus CInterpreter::Parenthesize(const String& In, String &Left, String &Right)
{
  return Itemize(In, Left, Right, String("()"));
  /*
  String Temp = In;
  SSI_INT64 CParPos = -1;
  SSI_INT64 ParenCtr = 0;

  CParPos = -1;
  while((CParPos = Temp.FindOneOf("()", CParPos)) >= 0)
  {
    if(Temp[CParPos] == '(')
    {
      ParenCtr++;
      CParPos++;
    }
    else
    {
      ParenCtr--;
      if(ParenCtr < 0) break;
      CParPos++;
    }
  }
  if(CParPos < 0) return STAT_ERR;
  if(ParenCtr >= 0) return STAT_ERR;

  Left = Temp.Left(CParPos);
  Right = Temp.Right(Temp.GetLength() - CParPos - 1);
  return STAT_OK;
  */
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

CStatus CInterpreter::Bracketize(const String& In, String &Left, String &Right)
{
  return Itemize(In, Left, Right, String("[]"));
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

CStatus CInterpreter::Itemize(const String& In, String &Left, String &Right, String Delims)
{
  String Temp = In;
	Temp.SetQuoteState(In.GetQuoteState());
  SSI_INT64 CParPos = -1;
  SSI_INT64 ParenCtr = 0;

	SSI_INT64 EndParenInd = -1;
	SSI_INT64 StartParenInd = -1;


  if(Delims.GetLength() != 2)
  {
    return CStatus(sERROR, ERR03004);
  }

  SSI_CHAR start = Delims[0];
  SSI_CHAR end = Delims[1];

  CParPos = -1;
  while((CParPos = Temp.FindOneOf(Delims, CParPos)) >= 0)
  {
    if(Temp[CParPos] == start){
      ParenCtr++;
			if(ParenCtr == 1){
				StartParenInd = CParPos;
			}
      CParPos++;
    }else{
      ParenCtr--;
			if(ParenCtr == 0){
				EndParenInd = CParPos;
				break;
			}
      CParPos++;
    }
  }
	if(ParenCtr < 0){
		// These errors never caught...
		return STAT_FAIL;
		//MAKEERR1(ERR03005, start);
	}
	if(ParenCtr > 0){
		return STAT_FAIL;
		//MAKEERR1(ERR03006, end)
	}

	if((StartParenInd < 0) || (EndParenInd < 0)){  // No tokens
		Left = In;
		return STAT_FAIL;
	}

	Left = Temp.SubString(StartParenInd+1, EndParenInd-1);//   .Left(CParPos);
  Right = Temp.Right(Temp.GetLength() - EndParenInd - 1);
  return STAT_OK;

}

/////////////////////////////////////////////////////////////////////
//  Function:    CInterpreter::find_special
//  Scope:       Private
//  Parameters: 
//    String Line:      The string to to search
//    String OpSet:     The list of elements to search for
//    String &Ret:      Will contain the valid element found
//  Return:
//    SSI_INT64:            The index of the valid element found. -1 if none.
//  Modification History:
//    04/06/03:  Initial comments
//  Description:
//    Returns the position of an element (char) in OpSet if it is not
//    within quotes and not within a bracket set like [] or ().  Tracks
//    counters for each bracket set and the modulous of the quote.
//    Also checks for quote escape characters, and will not count a 
//    bracket if within quotes.  Returns the position of the valid
//    element.  Returns the element found through Ret.
//
/////////////////////////////////////////////////////////////////////
SSI_INT64 CInterpreter::find_special(const String& Line, const String& OpSet, String &Ret)
{
  SSI_INT64 ctr_list[NUM_BRACKETS];
  SSI_INT64 i = 0;
  SSI_INT64 j = 0;
  SSI_INT64 k = 0;
  SSI_INT64 q_ctr = 0;
  SSI_BOOL bRet;
  SSI_BOOL bFind = 0;

  String Temp = Line;
  String S;
  String sTemp1;
  String sTemp2;
  String Q;
  
	Q.SetAt(0, Q_SSI_CHAR);
	//Q.Format("%c", Q_SSI_CHAR);

  for(i = 0; i < NUM_BRACKETS; i++)
  {
    ctr_list[i] = 0;
  }
  for(j = 0; j < Temp.GetLength(); j++)
  {
    //S.Format("%c", Temp[j]);
		S.SetAt(0, Temp[j]);
    for(i = 0; i < NUM_BRACKETS; i++)
    {
      StartBrackList[i]->Get(sTemp1);
      StopBrackList[i]->Get(sTemp2);
      if(S == sTemp1)
      {
        if(!(q_ctr % 2))
        {
          ctr_list[i]++;
          bFind = 1;
        }
      }
      else if(S == sTemp2)
      {
        if(!(q_ctr % 2))
        {
          ctr_list[i]--;
          bFind = 1;
        }
      }
    }
    if(bFind)
    {
      bFind = 0;
    }
    else if(S == Q)
    {
      if(j == 0)
      {
        q_ctr++;
      }
      else if(Temp[j-1] != ESCAPE_SSI_CHAR)
      {
        q_ctr++;
      }
    }
    else if(OpSet.Find(S) >= 0)
    {
      bRet = 1;
      for(k = 0; k < NUM_BRACKETS; k++)
      {
        if(ctr_list[k] != 0) bRet = 0;
      }
      if(q_ctr % 2) bRet = 0;
      if(bRet)
      {
				Ret.SetAt(0, Temp[j]);
        //Ret.Format("%c", Temp[j]);
        return j;
      }
    }    
  }
  return -1;  
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

DimNode CInterpreter::GetArrayDimensions(const String& Input, String &Output)
{
  String Inp = Input;
  SSI_INT64 Pos = 0;
  SSI_INT64 Dim = 0;

  String oBrack = "[";
  String Value;
  CVariable aVar;

  String RetString;

  Pos = Inp.Parse(oBrack, RetString);
  if(Pos <= 0)
  {
   Output = Inp;
   return NULL_NODE;
  }

	Inp = Input;

  DimNode Ret = new_array_node();
  DimNode RetDim = Ret;

  while(Bracketize(Inp, Value, Inp))
  {
    if(!Evaluate(Value, aVar))
    {

       // DELETE THE DIM ARRAY
      del_array_node(RetDim);
      RetDim = SSI_NULL;
       //return SSI_NULL;
      return ERROR_NODE;
    }
		if(aVar.GetType() != CDataInt::GetRegisteredType())  // This needs to stay as a CDataInt
    {
      del_array_node(RetDim);
      RetDim = SSI_NULL;
       // create some sort of status error
       //return SSI_NULL;
      return ERROR_NODE;
    }
    CDataInt* anInt = (CDataInt*)&aVar.Get();
    if(Ret->Dim)
    {
      Ret->Next = new_array_node();
      Ret = Ret->Next;
    }
    
    Dim = anInt->GetData() + IS_ZERO_BASED_ARRAYS;
    if(anInt <= 0)
    {
      // Error Out
      //return SSI_NULL;
			del_array_node(RetDim);
			RetDim = SSI_NULL;
      return ERROR_NODE;
    }
    Ret->Dim = Dim;
    //Pos = Inp.Parse(oBrack, Value);  // Value is just used here as a place holder
    //if(Pos<=-1) break;
  }
  Output = RetString;
  return RetDim;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

/*
SSI_CHAR CInterpreter::CheckFlow(const String& In)
{
  SSI_INT64 Pos = -1;
  char* toks = " (";
  String Left;
  Pos = In.FindOneOf(toks);
  if(Pos <= 0) return 0;
  Left = In.Left(Pos);

  if(Left == "for") return 1;
  else if(Left == "if") return 1;
  else if(Left == "while") return 1;
  else if(Left == "switch") return 1;
  else return 0;
}
*/

// Remove the above function, cause not needed if we use
// this appropriately

// It may be best to let the conditional handle the evaluation...
//   this may be done via Callbacks?
//   Also... should the conditional evaluate itself?  Me thinks so.
//   However, the interpreter needs to set it up.

SSI_BOOL CInterpreter::GetNextLine(CScriptLine& Ret)
{
  if(!Input) return 0;
  if(Input->GetNextLine(Ret))
  {
		SeparateToStatements(Ret, *StatementList);
    DeComment(Ret.Line);
    return 1;
  }
  else
  {
    return 0;
  }
}

SSI_BOOL CInterpreter::GetCurrLine(CScriptLine& Ret)
{
	
	ScriptNode* aNode;
	if(!Input) return 0;
	aNode = Input->GetCurrLine();
	if(!aNode) return 0;
	aNode->Get(Ret);
	return 1;

	/*
  if(Input->GetNextLine(Ret))
  {
		SeparateToStatements(Ret, StatementList);
    DeComment(Ret.Line);
    return 1;
  }
  else
  {
    return 0;
  }
	*/
}


/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
CStatus CInterpreter::EvaluateFlow(const String& In, CFlowStruct &InFlow)
{
	// OK, here is the new strategy
	// Separate the statement by open paren
	//  Trim out the first word
	//  If it is a flow keyword 
	//   These are the keywords (each is a whole word):
	//    - if, else, while, for, else if, else while, else for
	//   Process the flow
	//  Else
	//   It is not a flow, return STAT_OK

	char* toks = "(";

	SSI_INT64 Pos = -1;
  //String In = Return;
	

	Pos = In.FindOneOf(toks);
  if(Pos > 0)
  {
    String KeyWd;
		KeyWd = In.Left(Pos);
		KeyWd.Trim();

		if(KeyWd == FLOW_FOR) InFlow.Type = COND_FOR;
		else if(KeyWd == FLOW_IF) InFlow.Type = COND_IF;
		else if(KeyWd == FLOW_WHILE) InFlow.Type = COND_WHILE;
		else if(KeyWd == FLOW_ELSE_IF) InFlow.Type = COND_ELSE_IF;
		else if(KeyWd == FLOW_ELSE_FOR) InFlow.Type = COND_ELSE_FOR;
		else if(KeyWd == FLOW_ELSE_WHILE) InFlow.Type = COND_ELSE_WHILE;
    else if(KeyWd == FLOW_CATCH) InFlow.Type = COND_CATCH;
		else return STAT_OK;
		return STAT_SUCCESS;
	}else{
		// Else and try will not have an opening paren
		if(In == FLOW_ELSE){
			InFlow.Type = COND_ELSE;
			return STAT_SUCCESS;
    }else if(In == FLOW_TRY){
      InFlow.Type = COND_TRY;
      return STAT_SUCCESS;
    }
	}
	return STAT_OK;


/*
  // ----- Initialization -------
  SSI_CHAR* toks = FLOW_SEPARATORS;
  SSI_INT64 Pos = -1;
  String In = Return;
  int Diff = 0;
  SSI_BOOL bSetOpenBrace = 0;
  SSI_INT64 Len = 0;
  String Left;
  String Right;

  Pos = In.FindOneOf(toks);
  if(Pos <= 0)
  {
    Pos = In.Find(FLOW_OPEN_BRACE);
    if(Pos > 0){
      String OBrace = FLOW_OPEN_BRACE;
      Diff = OBrace.GetLength();
      bSetOpenBrace = 1;
    }
  }
  else{
    Diff = 1;
  }

  Len = In.GetLength();
  Left = In.Left(Pos);
  Right = In.Right(Len - Pos - Diff);

  Left.Trim();
  Right.Trim();

  if((Left == "") && (Right == FLOW_ELSE))
  {
    Left = FLOW_ELSE;
    Right = "";
  }

  if(Left == FLOW_FOR) InFlow.Type = COND_FOR;
  else if(Left == FLOW_IF) InFlow.Type = COND_IF;
  else if(Left == FLOW_ELSE) InFlow.Type = COND_ELSE;
  else if(Left == FLOW_WHILE) InFlow.Type = COND_WHILE;
  else if(Left == FLOW_SWITCH) InFlow.Type = COND_SWITCH;
  else return STAT_OK;

  // ----- Processing -------
  SSI_CHAR* Sep = FLOW_FOR_SEPARATOR;
  SSI_CHAR tok = 0;
  CStatus RetStat;
  
  if(bSetOpenBrace)
  {
    Right = Right + FLOW_OPEN_BRACE;
  }

  if(InFlow.Type != COND_ELSE)
  {
    RetStat = Parenthesize(Right, Left, Right);
    if(!RetStat) return RetStat;
  }

  // Remainder is set here
  Return = Right;
  StringTree sTree;
  StringNode* sNode;
	//VarTree pTree;
	//VarNode* pNode;
  String Line;
  CVariable Var;

  InFlow.checkLine = Input->GetCurrLine();
  if((InFlow.Type == COND_WHILE) || (InFlow.Type == COND_FOR))
  {
    InFlow.bTryAgain = 1;
    InFlow.bInitialized = gInitialized;
    gInitialized = 0;
  }

  if(InFlow.Type != COND_ELSE)
  {
		// Hmmm... this has the nasty habit of re-initializing, and computing
    RetStat = Parameterize(Left, sTree, Sep);
    if(!RetStat) return RetStat;
  }

  if(InFlow.Type == COND_FOR)
  {
    sNode = sTree.getTop(); 
    int ctr;

    for(ctr = 0; ctr < 3; ctr++)
    {
      if(!sNode){
        RetStat.Set(sERROR, String("'for' statement requires three parameters"));
        return RetStat;
      }
      sNode = sNode->next();
    }
    
    if(!InFlow.bInitialized)
    { 
      sTree[0]->Get(Line);  
      InFlow.bInitialized = 1;
    }
    else
    {
      sTree[2]->Get(Line);
    }
    RetStat = Evaluate(Line, Var);
    if(!RetStat) return RetStat;

		sTree[1]->Get(Line);
    RetStat = Evaluate(Line, Var);
    
		if(!RetStat) return RetStat;
    InFlow.bCond = Var.Get().boolean();
  }
  else if(InFlow.Type == COND_IF)
  {
    sNode = sTree.getTop(); 
    if(!sNode){
      RetStat.Set(sERROR, String("'if' statement requires one parameter"));
      return RetStat;
    }
    sNode->Get(Line);
    if(sNode->next()){
      RetStat.Set(sERROR, String("'if' statement requires one parameter"));
      return RetStat;
    }
    RetStat = Evaluate(Line, Var);
    if(!RetStat) return RetStat;
    InFlow.bCond = Var.Get().boolean();
  }
  else if(InFlow.Type == COND_ELSE)
  {
		// Temporary fix to fix }else if{ where previous was true
		if(InFlow.bCond == 1){
			InFlow.Type = COND_IF;  
		}
    InFlow.bCond = 0;
  }
  else if(InFlow.Type == COND_WHILE)
  {
    sNode = sTree.getTop(); 
    if(!sNode){
      RetStat.Set(sERROR, String("'while' statement requires one parameter"));
      return RetStat;
    }
    sNode->Get(Line);
    if(sNode->next()){
      RetStat.Set(sERROR, String("'while' statement requires one parameter"));
      return RetStat;
    }
    RetStat = Evaluate(Line, Var);
    if(!RetStat) return RetStat;
    InFlow.bCond = Var.Get().boolean();
  }
  else if(InFlow.Type == COND_SWITCH)
  {
  }
  return STAT_SUCCESS;
	*/
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

CStatus CInterpreter::FindEndOfFlow(const String& FirstString, CFlowStruct& Struct)
{
  const SSI_CHAR* Braces = "{}";
  String S;
  String Tok;

  int locBCtr = 0;
  String Temp = FirstString;
  if(Temp.Parse(Braces, S, &Tok)>=0)
  {
    if(Tok == "{")
    {
       locBCtr++;
    }
    else
    {
      locBCtr--;
      if(locBCtr <= 0)
      {
        Struct.endLine = Input->GetCurrLine();
        //Remainder = Temp;
        return STAT_OK;
      }
    }
  }

  CScriptLine aLine;
  while(Input->GetNextLine(aLine))
  {
    Temp = aLine.Line;
    DeComment(Temp);
    Temp.Trim();
    if(Temp.Parse(Braces, S, &Tok) >= 0)
    {
      if(Tok == "{")
      {
        locBCtr++;
      }
      else
      {
        locBCtr--;
        if(locBCtr < 0)
        {
          Struct.endLine = Input->GetCurrLine();
          return STAT_OK;
        }
      }
    } 
  }

  return CStatus(sERROR, ERR03007);
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/*
void CInterpreter::SetLastFlow(CFlowStruct *In)
{

  // This concept will not work in a nested flow situation
  //   Consider an else while (with last flow an else)
  //   Nested within is another loop, whereupon the last flow
  //   is set again when the flow is complete
  //   The parent else while will fail because the last flow
  //   is no longer an 'if'

  // We still need a temporary master lastflow
  //   Is set when a new flow is encountered
  //     after setting the flowstruct's lastflow
  //   Is cleared when flow is exited?


  if(In)
  {
    if(LastFlow)
    {
      delete LastFlow;
    }
    LastFlow = new CFlowStruct;
    *LastFlow = *In;
  }
  else
  {
    if(LastFlow)
    {
      delete LastFlow;
    }
    LastFlow = SSI_NULL;
  }
}
*/
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
//
// THIS FUNCTION DOES NOT ADD A FLOW IF THE CONDITION IS NOT 1
// THEREFORE POPPING A FLOW AFTERWARDS IS THE PREVIOUS FLOW
//

CStatus CInterpreter::ProcessFlow(String &Return, CFlowStruct &aFlow, SSI_BOOL bEval)
{
	CStatus RetStat;
	ScriptStatementNode* First;
	ScriptStatementNode* Last;
	ScriptStatementNode* CurrNode;
	CScriptStatement CurrStat;
	String Line;
	CVariable Var;
	SSI_BOOL bGo = 1;
	SSI_INT64 FirstIndex;
	SSI_INT64 LastIndex;
	SSI_INT64 BeginIndex;
	SSI_INT64 EndIndex;
	SSI_INT64 BCtr = 0;

	First = StatementList->GetCurrentStatement();				// Record the First Statement prior to processing
	FirstIndex = StatementList->GetCurrIndex();          // Record the index
	
	// Cycle through the statement list looking for opening braces and closing braces
	while(bGo){
		CurrNode = GetNextStatement(CurrStat);
		if(!CurrNode){
			// Ending Brace was never found
			MAKEERR0(ERR03315);
		}
		// REMINDER::: Make sure that the first statement is an open brace...
		if(CurrStat.Statement == FLOW_OPEN_BRACE){
			BCtr++;
			if(BCtr == 1){
				// If this is the first brace, begin at next statement
				BeginIndex = StatementList->GetCurrIndex() + 1;
			}
		}else if(CurrStat.Statement == FLOW_CLOSE_BRACE){
			BCtr--;
			if(BCtr < 0){
				// Opening Brace Never Found
				MAKEERR0(ERR03316);
			}else if(BCtr == 0){
				// If this is the last brace, end at previous statement
				EndIndex = StatementList->GetCurrIndex() - 1;
				// Break Out
				bGo = 0;
			}
			// Else, continue getting statements
		}else{
		}
	}
	// This is the ending statement
	Last = StatementList->GetCurrentStatement();
	LastIndex = StatementList->GetCurrIndex();

	// Go back to the beginning
	StatementList->SetCurrIndex(FirstIndex);  // Minus 1 to ensure we get the first parameter

	// Process each type of flow
	if((aFlow.Type == COND_IF) || ((aFlow.Type == COND_ELSE_IF) && aFlow.bCond)){
		String CheckString;
		String Component;
		int ctr;
		int Pos;

		CurrNode = StatementList->GetCurrentStatement();
		CurrNode->Get(CurrStat);
		CheckString = CurrStat.Statement;

		Pos = CheckString.Parse(FLOW_PARAM_START, Component);
		if(Pos <= 0){
			// Error out - Must have an open paren
			MAKEERR0(ERR03317);
		}
		CheckString.Reverse();
		Pos = CheckString.Parse(FLOW_PARAM_END, Component);
		String sTemp1 = Component;
		Component = CheckString;
		CheckString = sTemp1;
		Component.Reverse();
		CheckString.Reverse();
		if(Pos < 0){
			// Error out - Must have a closing paren
			MAKEERR0(ERR03318);
		}

		RetStat = Evaluate(Component, Var);
    if(!RetStat){
      return RetStat;
    }
	  bGo = Var.Get().boolean();
		
		if(bGo){
			// Empty the condition to prevent following else statements from going
			aFlow.bCond = 0;
		}else{
			// Allow following else statements to go...
			aFlow.bCond = 1;
		}

    // Set up an engine to process the flow
    CEngine* anEng = Engine->CreateFunctionEngine();
    anEng->SetLoopEngine();
    CEngine* oldEng = Engine;
    Engine = anEng;

		// If condition is OK, cycle through statements
		for(ctr = BeginIndex; (ctr <= EndIndex) && bGo; ctr++){


			CurrNode = StatementList->GetByIndex(ctr);
			CurrNode->Get(CurrStat);
			String sLine = CurrStat.Statement;
			// Evaluate current statement
			if(!(RetStat = Evaluate(sLine, Var))){
        ZAP_ENGINE

        return RetStat;
			}
			if(GetReturnState() || GetStopState()){
        ZAP_ENGINE

        return STAT_OK;
			}

			ctr = StatementList->GetCurrIndex();
		}

    ZAP_ENGINE

		// Go to end of flow, so can continue
		StatementList->SetCurrIndex(LastIndex);
	}else if((aFlow.Type == COND_ELSE) && aFlow.bCond){
		int ctr;

    // Set up an engine to process the flow
    CEngine* anEng = Engine->CreateFunctionEngine();
    anEng->SetLoopEngine();
    CEngine* oldEng = Engine;
    Engine = anEng;

		for(ctr = BeginIndex; (ctr <= EndIndex); ctr++){
			CurrNode = StatementList->GetByIndex(ctr);
			CurrNode->Get(CurrStat);
			String sLine = CurrStat.Statement;
			// Evaluate current statement
			if(!(RetStat = Evaluate(sLine, Var))){
        ZAP_ENGINE

				return RetStat;
			}
			if(GetReturnState() || GetStopState()){
				ZAP_ENGINE

        return STAT_OK;
			}

			ctr = StatementList->GetCurrIndex();
		}
    ZAP_ENGINE

		StatementList->SetCurrIndex(LastIndex);
	}else if(aFlow.Type == COND_TRY){
		int ctr;

    // TRY creates global variables ...
		for(ctr = BeginIndex; (ctr <= EndIndex); ctr++){
			CurrNode = StatementList->GetByIndex(ctr);
			CurrNode->Get(CurrStat);
			String sLine = CurrStat.Statement;
			// Evaluate current statement
			if(!(RetStat = Evaluate(sLine, Var))){
				// This is where catch processing occurs
        StatementList->SetCurrIndex(LastIndex);
        return RetStat;
			}
			if(GetReturnState() || GetStopState()){
				return STAT_OK;
			}
			ctr = StatementList->GetCurrIndex();
		}
		StatementList->SetCurrIndex(LastIndex);
  }else if((aFlow.Type == COND_CATCH) && !(aFlow.Exception.GetStatus())){

    CVariable Except;
    String CheckString;
		String Component;
		int Pos;

		CurrNode = StatementList->GetCurrentStatement();
		CurrNode->Get(CurrStat);
		CheckString = CurrStat.Statement;

		Pos = CheckString.Parse(FLOW_PARAM_START, Component);
		if(Pos <= 0){
			// Error out - Must have an open paren
			MAKEERR0(ERR03380);
		}
		CheckString.Reverse();
		Pos = CheckString.Parse(FLOW_PARAM_END, Component);
		String sTemp1 = Component;
		Component = CheckString;
		CheckString = sTemp1;
		Component.Reverse();
		CheckString.Reverse();
		if(Pos < 0){
			// Error out - Must have a closing paren
			MAKEERR0(ERR03381);
		}

		RetStat = Evaluate(Component, Except);
		if(!RetStat) return RetStat;

    if(Except.Get().Type != CDataException::GetRegisteredType()){
      // Error out - Must catch exceptions
      CDataException e;
      MAKEERR1(ERR03382, e.DataName.Str());
    }

    Except.SetData((CData*)(&(aFlow.Exception)));

		int ctr;

    // Set up an engine to process the flow
    // catch creates local variables
    CEngine* anEng = Engine->CreateFunctionEngine();
    anEng->SetLoopEngine();
    CEngine* oldEng = Engine;
    Engine = anEng;

		for(ctr = BeginIndex; (ctr <= EndIndex); ctr++){
			CurrNode = StatementList->GetByIndex(ctr);
			CurrNode->Get(CurrStat);
			String sLine = CurrStat.Statement;
			// Evaluate current statement
			if(!(RetStat = Evaluate(sLine, Var))){
				// This is where catch processing occurs
        // Engine->RemoveVariable(Except);
        ZAP_ENGINE

        return RetStat;
			}
			if(GetReturnState() || GetStopState()){
        //Engine->RemoveVariable(Except);
        ZAP_ENGINE

				return STAT_OK;
			}
			ctr = StatementList->GetCurrIndex();
		}

    ZAP_ENGINE
		StatementList->SetCurrIndex(LastIndex);
    //Engine->RemoveVariable(Except);
	}else if((aFlow.Type == COND_FOR) || ((aFlow.Type == COND_ELSE_FOR) && aFlow.bCond)){
		CurrNode = First;
		StringTree sTree;

		String Component;
		String CheckString;
		int ctr;
		int Pos;
		SSI_CHAR* Sep = FLOW_FOR_SEPARATOR;
		if(!RetStat) return RetStat;

		// Construct the Components
		for(ctr = 0; ctr < 3; ctr++)
		{
			// Ensure 3 parameters for 'for' statement
			if(!CurrNode){
				RetStat.Set(sERROR, String("'for' statement requires three parameters"));
				return RetStat;
			}

			// Get the statement
			CurrNode->Get(CurrStat);

			// Prepare the for parameters
			CheckString = CurrStat.Statement;

			// Ensure there is an open paren
			if(ctr == 0){
				Pos = CheckString.Parse(FLOW_PARAM_START, Component);
				if(Pos <= 0){
					// Error out - Must have an open paren
					MAKEERR0(ERR03319);
				}
				Component = CheckString;
			// Ensure there is a close paren
			}else if(ctr == 2){
				CheckString.Reverse();
				Pos = CheckString.Parse(FLOW_PARAM_END, Component);
				if(Pos < 0){
					// Error Out - Must have a closing paren
					MAKEERR0(ERR03320);
				}
				CheckString.Reverse();
				Component = CheckString;
			}else{
				Component = CheckString;
			}

			// Push for paremeter on the list
			sTree.push(Component);
			CurrNode = StatementList->GetNextStatement();
		}

		// Do the initialization
		sTree[0]->Get(Line);  
		RetStat = Evaluate(Line, Var);
		if(!RetStat) return RetStat;
		bGo = 1;
		while(bGo){
			
			// Do this so input can query the correct lines...
			StatementList->SetCurrIndex(FirstIndex);
			if(QueryInput() == 0){
				SetStopFlag();
				return STAT_OK;
			}

			// Check the for condition
			sTree[1]->Get(Line);
			RetStat = Evaluate(Line, Var);
			if(!RetStat) return RetStat;
	    bGo = Var.Get().boolean();

			// If condition is OK, cycle through statements
			if(bGo){
				// Cycle through statement indices

        // Set up an engine to process the flow
        CEngine* anEng = Engine->CreateFunctionEngine();
        anEng->SetLoopEngine();
        CEngine* oldEng = Engine;
        Engine = anEng;

				for(ctr = BeginIndex; ctr <= EndIndex; ctr++){
					CurrNode = StatementList->GetByIndex(ctr);
					CurrNode->Get(CurrStat);
					String sLine = CurrStat.Statement;
					// Evaluate current statement
					if(!(RetStat = Evaluate(sLine, Var))){
						ZAP_ENGINE

            return RetStat;
					}
					ctr = StatementList->GetCurrIndex();
  				if(GetReturnState() || GetStopState()){
            ZAP_ENGINE

						return STAT_OK;
					}

				}
        ZAP_ENGINE
				
				// Update Control Variable
				sTree[2]->Get(Line);
				RetStat = Evaluate(Line, Var);
				if(!RetStat) return RetStat;
			}
		}

		// Go to end of flow, so can continue
		//StatementList.SetCurrIndex(LastIndex);
		StatementList->SetCurrIndex(LastIndex);
	}else if((aFlow.Type == COND_WHILE) || ((aFlow.Type == COND_ELSE_WHILE) && aFlow.bCond)){
		String CheckString;
		String Component;
		int ctr;
		int Pos;

		CurrNode = StatementList->GetCurrentStatement();
		CurrNode->Get(CurrStat);
		CheckString = CurrStat.Statement;
		Pos = CheckString.Parse(FLOW_PARAM_START, Component);
		if(Pos <= 0){
			// Error out - Must have an open paren
			MAKEERR0(ERR03321);
		}
		
		// To ensure we get the last paren
		CheckString.Reverse();
		Pos = CheckString.Parse(FLOW_PARAM_END, Component);
		Component = CheckString;
		Component.Reverse();
		if(Pos < 0){
			// Error out - Must have a close paren
			MAKEERR0(ERR03322);
		}

		RetStat = Evaluate(Component, Var);
		if(!RetStat) return RetStat;
	  CData* bData = &Var.Get();
		if(bData){
			bGo = bData->boolean();
		}else{
			// Actually, return an error
			bGo = 1;
		}
		//bGo = Var.Get().boolean();
		String sLine;

		int q = 0;

		while(bGo){

			// Do this so input can query the correct lines...
			StatementList->SetCurrIndex(FirstIndex);
			if(QueryInput() == 0){
				SetStopFlag();
				return STAT_OK;
			}

      // Set up an engine to process the flow
      CEngine* anEng = Engine->CreateFunctionEngine();
      anEng->SetLoopEngine();
      CEngine* oldEng = Engine;
      Engine = anEng;

      // If condition is OK, cycle through statements
			for(ctr = BeginIndex; (ctr <= EndIndex) && bGo; ctr++){

				CurrNode = StatementList->GetByIndex(ctr);
				CurrNode->Get(CurrStat);
				sLine = CurrStat.Statement;
				// Evaluate current statement
				if(!(RetStat = Evaluate(sLine, Var))){
          ZAP_ENGINE

					return RetStat;
				}
				ctr = StatementList->GetCurrIndex();

   			if(GetReturnState() || GetStopState()){
          ZAP_ENGINE
					return STAT_OK;
			  }
			}

      ZAP_ENGINE

			RetStat = Evaluate(Component, Var);
			if(!RetStat) return RetStat;
		  
  	  bData = &Var.Get();
			if(bData){
				bGo = bData->boolean();
			}else{
				// Actually, return an error
				bGo = 1;
			}
		}
		// Go to end of flow, so can continue
		StatementList->SetCurrIndex(LastIndex);
	}else{
		// It must be a statement that follows an else, but is not OK to 
		// exec, therefore, set to the last index
		StatementList->SetCurrIndex(LastIndex);
	}

	return STAT_OK;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/*
CStatus CInterpreter::ProcessElse(String& Return, CFlowStruct &aFlow)
{
	CStatus RetStat;
  if(LastFlow)
  {
    if(LastFlow->Type == COND_IF)
    {
      CFlowStruct TempFlow;
      if(RetStat = EvaluateFlow(Return, TempFlow))
      {
        SSI_BOOL bIsElseOnly = 0;
        if(!(RetStat == STAT_SUCCESS))
        {
          if(Return.GetLength()) return CStatus(sERROR, ERR03011);
          bIsElseOnly = 1;
        }

        CFlowStruct* ptrFlow = SSI_NULL;
        
        // It is irrelevent if line is set here
        // it will be set after this function returns
        // So bCond does not need to be set yet
        // ACTUALLY... TempFlow.bCond MUST = 1, else
        //  ProcessFlow will pop a Flow
        if(bIsElseOnly || (LastFlow->bCond == 1))
        {
          TempFlow.bCond = 0;//1;
        }
        RetStat = ProcessFlow(Return, TempFlow);
        if(!RetStat) return RetStat;

        // Need to pop, because in ProcessFlow
        //  it was pushed, and will be pushed after
        //  altered here.

        aFlow = TempFlow;
        ptrFlow = LastFlow;  // Hmmm... will this work?

        if(!ptrFlow){
          return CStatus(sERROR, ERR03012);
        }
        if(ptrFlow->bCond != 0)
        {
          aFlow.bCond = DO_NOT_RUN;
        }
        else if(bIsElseOnly)
        {
          aFlow.bCond = 1;
        }
        
        // Because another flow was found

        // Must push here to set the last flow type
        //   So... 
        Input->PushPointer(aFlow);
        SetLastFlow(&aFlow);
      }
      else
      {
        return RetStat;
      }
    }
    else
    {
      return CStatus(sERROR, ERR03013);
    }
  }
  else
  {
    return CStatus(sERROR, ERR03014);
  }
  return STAT_SUCCESS;
}
*/

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

/*
CStatus CInterpreter::CheckFlowClose(String& sInput, CFlowStruct &aFlow)
{
  // ------ Initialization-------
  String Temp = sInput;
  int Pos = 0;
  SSI_BOOL bSuccess = 0;

  if((Pos = Temp.Find(FLOW_CLOSE_BRACE)) >= 0) // Check for (and parse for) a closing brace here, and pop the pointer
  {
    String CBrace = FLOW_CLOSE_BRACE;
    int Len = 0;

    Len = Temp.GetLength();
    Temp = Temp.Right(Len - Pos - CBrace.GetLength());
    Temp.Trim();
    BCtr--;
    if(BCtr < 0) 
    {
			String sErr;
			sErr.Format(ERR03015, FLOW_CLOSE_BRACE);
      return CStatus(sERROR, sErr);
    }

    Input->PopPointer(aFlow);
    if(aFlow.bTryAgain)
    {
      gInitialized = 1;
      gInitialized = aFlow.bInitialized;
      
      if(aFlow.checkLine->prev())
      {
        // --------------------------------------------------------
        // CHECK FOR A SSI_NULL
        Input->SetCurrLine(aFlow.checkLine->prev());
      }
      else
      {
        // Do something here
      }
      bSuccess = 1;
    }
    else
    {
			// Should be a temporary fix, because errors will then not show the whole line
			//CScriptLine aLine;
			//aFlow.endLine->Get(aLine);
			//aLine.Line = Temp;
			//aFlow.endLine->Set(aLine);
      Input->SetCurrLine(aFlow.endLine);        
      gInitialized = 0;
			sInput = Temp;
    }
		// This should be a temporary fix, because does not allow anything after closing brace
		// return STAT_SUCCESS;
  }

  // This means that it will try again
  if(bSuccess) return STAT_SUCCESS;
	return STAT_OK;
}
*/

CStatus CInterpreter::EvaluateKeyword(const String& inLine)
{
  String In = inLine;
  SSI_INT64 Pos = -1;
  String Keywd;
  Pos = In.Parse(KEYWORD_SEPARATORS, Keywd);
  if(Pos < 0){
		Keywd = In;
		ChopEnder(Keywd);
		In = "";
  }
  
	CKeywordDecl aDecl;
	aDecl.m_Keyword = Keywd;
	CStatus RetStat;

	RetStat = Engine->DoKeyword(aDecl, In);
	if(!RetStat) return RetStat;
	if(RetStat == STAT_SUCCESS) return STAT_SUCCESS;


  if(Keywd == "include"){
    //In.Trim();
		if(!ChopEnder(In)){
			MAKEERR1(ERR03100, STATEMENT_ENDER);
		}

    //CVariable Var;
    //Var.Name = In;
    //if(Engine->GetVariable(Var)){
    //}

    RetStat = Engine->GetKeywordStringInput(In);
    if(!RetStat){
      return RetStat;
    }

    return InterpretFile(In);
  }else if(Keywd == "clear"){
    ChopEnder(In);
    if(In.GetLength() > 0){
      CVariable Var;
      Var.Name = In;
      if(Engine->GetVariable(Var)){
        Engine->RemoveVariable(Var);
      }
    }else{
      Engine->ClearVariables();
    }
    return STAT_SUCCESS;
  }else if(Keywd == "unload"){
    ChopEnder(In);
    if(In.GetLength() > 0){
      Engine->RemoveFunction(In);
    }else{
      Engine->ClearFunctions();
    }
    return STAT_SUCCESS;
  }else if(Keywd == FUNCTION_KEYWORD){
    return CreateUserFunction(In);
	}else if(Keywd == "package"){
		ChopEnder(In);
		In.Trim();
		CDataString aStr;
		if(!aStr.DataFromString(In)){
			MAKEERR0(ERR03390);
		}
		aStr.Data.Trim();
		if(In.GetLength() > 0){
			Engine->UserPackageName = aStr.Data;
		}else{
      MAKEERR0(ERR03391);
		}
    return STAT_SUCCESS;
  }else if(Keywd == "return"){
		if(!ChopEnder(In) && In.GetLength() > 0){
			MAKEERR1(ERR03101, STATEMENT_ENDER);
		}
    return DoFunctionReturn(In);
	//}else if(Keywd == "class"){
	//	return CreateUserClass(In);
	}else if(Keywd == "exit"){
		bStopFlag = 1;
		return STAT_SUCCESS;
	}

  else{
    return STAT_OK;
  }
  return STAT_OK;
}

CStatus CInterpreter::InterpretFile(String& FileName)
{

  CDataString aString;
  //if(!aString.DataFromString(FileName)) return CStatus(sERROR, ERR03202);
  if(aString.DataFromString(FileName)){
    FileName = aString.Data;  // String check is now performed in the "include" processor
  }

	//if(!FileName.CheckEndQuotes(1, 1)) return CStatus(sERROR, ERR03202);

  CScript aScript(out, in);
	
  aScript.RunMode = Input->RunMode;   // Make sure run mode is the same
	aScript.Debugger = Input->Debugger;

  // Environment directory stuff
  String FullFile;
  CStatus Ret = Engine->Environment->GetAbsolutePath(FileName, FullFile);
  if(!Ret){
    return Ret;
  }
  FileName = FullFile;

  if(!aScript.Load(FileName)){
		//return (CStatus::MakeStatus().Format(sERROR, "File could not be opened: %s", FileName.Str()));
    MAKEERR1(ERR01110, FileName.Str());  
  }
  CInput* TempInput = Input;
  Input = &aScript;


  CScriptStatementList* OldList = StatementList;
	CScriptStatementList* NewList = new CScriptStatementList;
  StatementList = NewList;

	if(!aScript.Run(Input->RunMode, this)){
    Input = TempInput;  // why was this commented?
    StatementList = OldList;
    delete NewList;
    //String Mess = "Error evaluating file ";
    //Mess = Mess + FileName;
    MAKEERR1(ERR01111, FileName.Str());  
  }
  Input = TempInput;
  StatementList = OldList;
  delete NewList;

  return STAT_SUCCESS;
}

// --eff-- make more efficient
CStatus CInterpreter::CreateUserFunction(const String& inLine)
{
	CFunctionDecl aDecl;
	CStatus Ret;
	String loc = inLine;
	String Temp;
	String ClassName;
	String Tok;
	String Sep = CLASS_FUNC_SEPARATOR;
	CStatus RetStat;

	Ret = DeclareUserFunction(loc, aDecl);  // inLine now contains the remainder
	aDecl.FileName = Input->GetFileName();

	CScriptStatement aStat;
	ScriptStatementNode* aNode = 0; // = StatementList->GetCurrentStatement();
	aNode = GetNextStatement(aStat);
	while(aNode){   // Get all remaining statements and put them in a composite
		aNode->Get(aStat);
		loc = loc + aStat.Statement;
		aNode = aNode->next();  //GetNextStatement(aStat);
	}

	if(!Ret) return Ret;

	// if loc begins with a brace, or is not a ';', then define.
	// Need to ensure that the ';' is not stripped earlier

  loc.SetQuoteState(1);
	if(loc.Find(FUNCTION_OPEN_BRACE) >= 0){
		Ret = DefineUserFunction(loc, aDecl);
		if(!Ret) return Ret;
	}else if(!ChopEnder(loc)){
		Ret = DefineUserFunction(loc, aDecl);
		if(!Ret) return Ret;
	}

	Temp = aDecl.Name;
	if(Temp.Parse(Sep, ClassName, &Tok, Sep.GetLength()) >= 0){
		aDecl.Name = Temp;
		CClassDecl aClass;

		aClass.ClassName = ClassName;
		Ret = Engine->FindClassDecl(aClass);
		if(!Ret) return Ret; // Class not defined

		//aFunc.Set(aDecl);
		Ret = aClass.RepClass->AddFunction(aDecl);
		if(!Ret) return Ret; // Function not declared or already defined
	}else{
		Engine->SetPackageName(Engine->UserPackageName.Str());
		RetStat = Engine->AddFunction(aDecl);
	}

	// This will have to wait
	//DeComment(loc);
	//loc.Trim();
	//if((loc.GetLength()) > 0){
		// Junk after... dont want.
	//	return STAT_ERR;
	//}

  if(!RetStat) return RetStat;
	return STAT_SUCCESS;

}
CStatus CInterpreter::DeclareUserFunction(String& inLine, CFunctionDecl& newDecl)
{
  CStatus RetStat;
  String Temp = inLine;
  
	String Param;
	StringTree ParamTree;
  StringNode* pNode = SSI_NULL;

  String Ret;
  SSI_INT64 Pos = 0;
  SSI_INT64 nType = 0;

	newDecl.Flags = USER_FUNCTION_TYPE;

  Pos = Temp.Parse(FUNCTION_RETURNTYPE_SEPARATOR, Ret);
  if(Pos < 0){
    //String Mess = "Missing function return type";
    //return CStatus(sERROR, Mess);
    MAKEERR0(ERR01112);  
  }

  if(Ret.GetLength() <= 0){
    //String Mess = "Missing function return type";
    //return CStatus(sERROR, Mess);
    MAKEERR0(ERR01113);  
  }

  nType = GetVariableType(Ret);
  if(!nType){
    //String Mess;
		//Mess.Format("Unrecognized return type: %s", Ret.Str());
    //return CStatus(sERROR, Mess);
    MAKEERR1(ERR01114, Ret.Str()); 
  }

  // Set the return type
  newDecl.ReturnType = nType;
  
  Pos = Temp.Parse(FUNCTION_NAME_SEPARATOR, Ret);
  if(Pos < 0){
    //String Mess = "Invalid function declaration";
    //return CStatus(sERROR, Mess);
    MAKEERR0(ERR01115); 
  }

  if(Ret.GetLength() <= 0){
    //String Mess = "Missing function name";
    //return CStatus(sERROR, Mess);
    MAKEERR0(ERR01116); 
  }

  // Set the function name
  newDecl.Name = Ret;

  Pos = Temp.Parse(FUNCTION_PARAM_CLOSER, Ret);
  if(Pos < 0){
    //String Mess = "Invalid function declaration";
    //return CStatus(sERROR, Mess);
    MAKEERR0(ERR01117); 
  }

	// Temp now has the remainder, and must be set to the returned string;
	inLine = Temp;

	Temp = Ret;
  
  RetStat = Parameterize(Temp, ParamTree, FUNCTION_PARAM_SEPARATOR);
  if(!RetStat) return RetStat;

  SSI_INT64 numParams = 0;
  SSI_INT64 ctr = 0;
  
  String pName;
  String pType;
  String startFunc = Temp;

  while(pNode = ParamTree[ctr]){
    numParams++;
    ctr++;

    pNode->Get(Param);
    if(Param.GetLength() <= 0){
      //String Mess;
      //Mess.Format("Function parameter %d is invalid", ctr);
      //return CStatus(sERROR, Mess);
      MAKEERR1(ERR01118, ctr); 
    }
    
    Param.Trim();

    Pos = Param.Parse(FUNCTION_PARAM_TYPE_SEPARATOR, pType);
    if(Pos <= 0){
      //String Mess;
      //Mess.Format("Missing type in function parameter %d", ctr);
      MAKEERR1(ERR01119, ctr); 
    }

    pName = Param;
    pName.Trim();

    // Need a function to check for a valid variable name

    pType.Trim();
    
    nType = GetVariableType(pType);
    if(!nType){
      //String Mess;
      //Mess.Format("Unrecognized variable type: %s", pType);
      MAKEERR1(ERR01120, pType.Str()); 

    }

    if(pName.GetLength() <= 0){
      //String Mess;
      //Mess.Format("Missing variable name for parameter %d", ctr);
      MAKEERR1(ERR01121, ctr); 
    }
    newDecl.addType(nType, pName);
  }

	return STAT_OK;
}

CStatus CInterpreter::DefineUserFunction(String& inLine, CFunctionDecl& newDecl)
{
	// At end of function, inLine should be "" because
	// do not want junk at end of function definition.

	CStatus RetStat;
	String currLine = inLine;
	CScriptStatement aStatement;
	CComponentParser aParser;

	ScriptComponentT Component;
	ComponentItor Itor;

	CScriptLine aLine;

	int locBCtr = 0;
	SSI_BOOL bGo = 1;
	SSI_BOOL bAddItem = 0;
	Input->GetCurrLine()->Get(aLine);
	aLine.Line = inLine;
	String Composite;

	do{
		currLine = aLine.Line;
    currLine.SetQuoteState(1);
    
		// This will remove all comments from the function in execution
		// Fixes one of the bugs...
    DeComment(currLine);
    currLine.Trim();

		RetStat = aParser.ParseLine(currLine);
		if(!RetStat){
			return RetStat;
		}

		Itor = aParser.begin();
		//aNode = aParser.GetTop();
		while(Itor != aParser.end()){
			Component = *Itor;
			//aNode->Get(Component);
			if(Component.Component == FUNCTION_OPEN_BRACE && Component.Type == COMPONENT_TOKEN){
				locBCtr++;
			}else if(Component.Component == FUNCTION_CLOSE_BRACE && Component.Type == COMPONENT_TOKEN){
				locBCtr--;
				if(locBCtr == 0) bGo = 0;
			}
			if(bAddItem && locBCtr > 0){  // Dont add item after last brace
				Composite = Composite + Component.Component;
			}
			if(locBCtr > 0){
				bAddItem = 1;
			}else{
				bAddItem = 0;
			}
			++Itor;
			//aNode = aNode->next();
		}
		aLine.Line = Composite;
		newDecl.ScriptLines.push(aLine);
		Composite = "";  // Clear the composite
	}while(bGo && Input->GetNextLine(aLine));  // Order here is important

	if(bGo && locBCtr){
    //String Mess;
    //Mess.Format("Function end brace not found");
    MAKEERR0(ERR01122); 
	}else if(bGo){
	  //String Mess;
    //Mess.Format("Function open brace not found");
    MAKEERR0(ERR01123); 
	}
	
	newDecl.bIsDefined = 1;
	return STAT_SUCCESS;

  //{
  //String Mess;
	//MAKEERR1(ERR03212, FUNCTION_OPEN_BRACE);
  //}
	//currLine = aStatement.Statement;



	// --------------------------------------------------------
	// Here is where we separate this function
	// The above will remain as is...  and add the
	// ability to check for ';' or '{' or '\n'.  If
	// ';' is found, consider it a declaration only,
	// attempt to add it, and return.
	//
	// If not a ';', consider it a declaration and
	// a definition, and proceed to define it using the
	// code below.  If the function does not exist,
	// then add the new function, then define.  If it
	// does exist, ensure it is not already defined, then
	// grab it and define it.
	//
	// ** NOTE THAT NEITHER OF THESE SHOULD ACTUALLY ADD
	// THE DECLARATION, BUT SHOULD RETURN IT SO IT CAN BE
	// ADDED UPON SUCCESS IN EITHER REGULAR INTERPRETER
	// OR CLASS CREATION OR WHATEVER.
	// --------------------------------------------------------

  // OK, now we want to define the bounds of the function
  //SSI_BOOL bGo = 1;
	SSI_INT64 Pos;
	String Temp;
  SSI_INT64 Len = 0;

//	int locBCtr = 0;

	currLine = inLine;  // inLine contains entire remainder if after a declare
  while(bGo)
  {
    DeComment(currLine);
    currLine.Trim();

    if((Pos = currLine.Parse(FUNCTION_OPEN_BRACE, Temp)) >= 0){
      bGo = 0;
			currLine.Trim();
      // Do something with remainder (currLine)
    }
    else{
			//CScriptStatement aStatement;
      if(!(currLine == ""))
      {
        String Mess;
				MAKEERR1(ERR03211, FUNCTION_OPEN_BRACE);
      }
      //if(!Input->GetNextLine(aLine))
			if(!GetNextStatement(aStatement))
      {
        String Mess;
				MAKEERR1(ERR03212, FUNCTION_OPEN_BRACE);
      }
			currLine = aStatement.Statement;
    }
  }

  const SSI_CHAR* Braces = FUNCTION_BRACES;

	//CScriptStatement aStatement;
//	CScriptLine aLine;

  String Tok;

  bGo = 1;

	if(currLine.GetLength() > 0){
		// Necessary for a later push.
		Input->GetCurrLine()->Get(aLine);
		aLine.Line = currLine;
	}else{
		
		if(!GetNextStatement(aStatement)){
			// No more lines and no closing brace
			MAKEERR1(ERR03201, FUNCTION_CLOSE_BRACE);
		}
		currLine = aStatement.Statement;
		Input->GetCurrLine()->Get(aLine);
		aLine.Line = currLine;

	}

	do
  {
		currLine = aLine.Line;
    DeComment(currLine);
    currLine.Trim();
		Len = currLine.GetLength();
    if((Pos = currLine.Parse(Braces, Temp, &Tok)) >= 0) // CurrLine is remainder! Temp is parsed val
    {
      if(Tok == FUNCTION_OPEN_BRACE)
      {
        locBCtr++;
      }
      else
      {
        locBCtr--;
        if(locBCtr < 0)
        {
					// Last brace... if we chop it here
					// then we can add a last line
					// that includes a brace.

					bGo = 0;
					if(Pos != Len - 1){
						// There is junk afterwards, must error
						return CStatus(sERROR, ERR03202);
					}
					aLine.Line = Temp; // This is what was parsed out
        }
      }
    }
    
    // This doesnt allow braces at the end of a line
    //if(bGo){
      newDecl.ScriptLines.push(aLine);
    //}
  }while(bGo && Input->GetNextLine(aLine));  // Order here is important

  if(bGo){
    //String Mess;
    //Mess.Format("Function end brace not found");
    MAKEERR0(ERR01124); 
  }

	newDecl.bIsDefined = 1;
	return STAT_SUCCESS;
}

CStatus CInterpreter::ProcessUserFunction(CFunction &aFunc, CFunctionDecl &aDecl)
{

  CEngine* anEng = Engine->CreateFunctionEngine();

	// Protection stuff
	//if(aDecl.Access > ACCESS_GLOBAL){
		// Now we are going internal to the class function
		// Engine->CallingClass->IsExternalCall = 0;
		// anEng->CallingClass = Engine->CallingClass;
	//}else{
	//	anEng->CallingClass = SSI_NULL;
	//}

  CEngine* oldEng = Engine;
  CVariable aVar;
  String s;
  CStatus RetStat;
  SSI_INT64 NumParams = 0;
  SSI_INT64 ctr = 0;
  if(anEng == SSI_NULL) return CStatus(sERROR, ERR02016);

  Engine = anEng;

  NumParams = aFunc.GetNumParams();
  for(ctr = 0; ctr < NumParams; ctr++)
  {
    aVar = aFunc.GetVariable(ctr);
    s = aDecl.getParamName(ctr);
    if(!(RetStat = Engine->CopyVariable(aVar, s))){
      return RetStat;
    }
  }

  ScriptNode* aNode;
  CScriptLine aLine;
  String sLine;
  ctr = 0;
  SSI_BOOL bGo = 1;

  CFunctionInput anInput(in, out);
  //dont do this, since engine will be set when run
	//anInput.Engine = Engine;
	anInput.RunMode = Input->RunMode;
	anInput.Debugger = Input->Debugger;
  anInput.SetFunctionName(aDecl.Name);
	anInput.SetFileName(aDecl.FileName);

  while((aNode = aDecl.ScriptLines[ctr]) && bGo)
  {
    aNode->Get(aLine);
    anInput.AddLine(aLine);
    ctr++;
  }

  CInput* oldInput = Input;
  Input = &anInput;

	CScriptStatementList* OldList = StatementList;
	CScriptStatementList* NewList = new CScriptStatementList;

	StatementList = NewList;


  // REMOVE
  //anInput.bDeleteMembers = 0;


	if(!anInput.Run(Input->RunMode, this)){
      Engine = oldEng;
      Input = oldInput;
			StatementList = OldList;
			delete NewList;
      delete anEng;
      MAKEERR1(ERR01125, aFunc.Name.Str()); 
  }
  

	delete NewList;
	StatementList = OldList;
	bFunctionReturnState = 0;

	// Make sure Return state is set... as of now it isnt...
  if(anInput.bReturnState){
        aFunc.SetReturn(anInput.ReturnVar);
  }else{
    CVariable VoidVar;
    VoidVar.SetType(CDataVoid::GetRegisteredType());
    aFunc.SetReturn(VoidVar);
  }

  Engine = oldEng;
  Input = oldInput;
  delete anEng;
  return STAT_OK;
}

CStatus CInterpreter::DoFunctionReturn(const String& Input)
{
  CVariable Var;
  CStatus RetStat;
	if(Input.GetLength() > 0){
		RetStat = Evaluate(Input, Var);
		if(!RetStat) return RetStat;
	}else{
		Var.SetType(CDataVoid::GetRegisteredType());
	}
  bFunctionReturnState = 1;
  FunctionReturnVariable = Var;
  return STAT_SUCCESS;
}

CVariable CInterpreter::GetFunctionReturnVar()
{
  return FunctionReturnVariable;
}

SSI_BOOL CInterpreter::GetReturnState()
{
  return bFunctionReturnState;
}

void CInterpreter::ClearReturnState()
{
  FunctionReturnVariable.SetType(SSI_NULL);
  bFunctionReturnState = 0;
}

CStatus CInterpreter::CreateUserClass(const String& inLine)
{
	CStatus RetStat;
	CClassDecl aDecl;
	String s = inLine;

	aDecl.ClassName = s;
	// Need to be added before define, next statement handles full declare
	//  since define will add to existing lists
	RetStat = Engine->AddClass(aDecl);
	if(!RetStat) return RetStat;

	RetStat = DeclareUserClass(s, aDecl);
	if(!RetStat) return RetStat;


	//RetStat = DefineUserClass(s, aDecl);
	//if(!RetStat) return RetStat;

	return STAT_SUCCESS;

	// Create a class in the Engine, add to Engine's
	// declared classes to delete later
	// Engine will handle all class processing, since
	// it is the job of the interpreter to handle only
	// syntax related issues...  This is to include 
	// finding, tracking, and adding.

	// Check if class already exists and is defined

	// Not gonna worry about superclasses just yet
	//if(Tok == CLASS_SUPERSEPARATOR){
	//	if(s.Parse(CLASS_DECL_ENDERS, Temp, &Tok){
	//	}else{
	//	}
	//}else if(s.Parse(CLASS_SUPERSEPARATOR, Temp) >= 0){
	//}

	// SPLIT THIS INTO DECLARE CLASS AND DEFINE CLASS?
	//   Only, define defines the structure of the class,
	//   not the actual function definitions...
	//   Yes, me thinks so, so we can have 'class aclass;'

	// Get the class name
	// Get the class superclass, if exists
	// Create the new class?  Or should engine handle this?  No... this is a 
	//   syntax issue, so Interpreter should create

	// If a brace,
	//   go through lines til end brace
	//   Add functions and data as encountered
	//   C++ requires a ';' at the end...

	// If a semi-colon - need to declare temprary class, I guess

	// I should generalize the CreateUserFunction stuff to allow for
	//   function declarations, with function definitions set later.
	//   This needs to be done prior to coding this so I can use the same 
	//   function to create the functions in this class.
	//   ------> Done.
	// May need an intermediate function, whereby if ends with a ';'
	//   then only add the declarations, else try to add the 
	//   definition, too.
	//   ------> Done.

	// Nested classes will not be supported in this version.
}

CStatus CInterpreter::DeclareUserClass(String& inLine, CClassDecl& newDecl)
{
	String s = inLine;
	String Tok;
	String Temp;
	//String ClassName;
	String SuperClass;
	CStatus RetStat;

	SSI_BOOL bFoundBrace = 0;
	SSI_BOOL bGo = 1;

	ScriptStatementNode* CurrNode;
	CScriptStatement CurrStat;
	SSI_INT64 Pos = 0;


	// Name should = inLine
	// ClassName = inLine;
	// newDecl.ClassName = inLine;
	RetStat = Engine->FindClassDecl(newDecl);
	if(!RetStat) return RetStat;
	while(bGo){
		CurrNode = GetNextStatement(CurrStat);
		if(!CurrNode){
			// Closing or opening brace never found... check bFoundBrace
			return STAT_ERR;  // Internal (CLASS)
		}
		if(CurrStat.Statement == CLASS_OPEN_BRACE){
			if(bFoundBrace){
				// Brace already found, so say boop.
				return STAT_ERR; // Internal (CLASS)
			}else{
				bFoundBrace = 1;
			}
		}else if(CurrStat.Statement == CLASS_CLOSE_BRACE){
			bGo = 0;

			return STAT_OK;
			// add the class, return OK
		}else{
			s = CurrStat.Statement;
			s.Trim();
			Pos = s.Parse(CLASS_MEMBER_SEPARATOR, Temp, &Tok);
			// If length and no open brace, return error
			s.Trim();
			if((s.GetLength() > 0) && !bFoundBrace){
				// Need open brace
				return STAT_ERR; // Internal (CLASS)
			}
			if(!ChopEnder(s)){
				MAKEERR1(ERR03206, STATEMENT_ENDER);
			}
			if(Pos >= 0){
				SSI_INT64 VarType = 0;
				String VarName;
				CVariable aVar;
				CFunctionDecl funcDecl;

				if(Temp == FUNCTION_KEYWORD){
					RetStat = DeclareUserFunction(s, funcDecl);
					if(!RetStat) return RetStat;
					s.Trim();
					//if(!(s == STATEMENT_ENDER)){
						// Statement ender expected
					//	MAKEERR1(ERR03206, STATEMENT_ENDER);
					//}
					//funcDecl.Access = CurrProt;
					RetStat = newDecl.RepClass->AddFunction(funcDecl);
					if(!RetStat) return RetStat;
				}else if(VarType = GetVariableType(Temp)){

					//if((Pos = s.Parse(String(STATEMENT_ENDER), Temp, &Tok)) < 0){
					//	// Statement ender expected
					//	MAKEERR1(ERR03207, STATEMENT_ENDER);
					//}
					s.Trim();
					//if(s.GetLength() > 0){
						// Nothing expected after statement ender
					//	return CStatus(sERROR, ERR03208);
					//}
					VarName = s;
					VarName.Trim();
					aVar.Name = VarName;
					aVar.SetType(VarType);
					// aVar.Access = CurrProt;
					// Is this an OK variable name?
					RetStat = newDecl.RepClass->AddNewVariable(aVar);
					if(!RetStat) return RetStat;
				}else{
				// Unrecognized sequence
					return CStatus(sERROR, ERR03209);
				}
			}
		}
	}

/*
	else if((Pos = currLine.Parse(String(CLASS_MEMBER_SEPARATOR), Temp, &Tok)) >= 0){
			if(Temp == FUNCTION_KEYWORD){
				RetStat = DeclareUserFunction(currLine, funcDecl);
				if(!RetStat) return RetStat;
				currLine.Trim();
				if(!(currLine == STATEMENT_ENDER)){
					// Statement ender expected
					MAKEERR1(ERR03206, STATEMENT_ENDER);
				}
				funcDecl.Access = CurrProt;
				RetStat = newDecl.RepClass->AddFunction(funcDecl);
				if(!RetStat) return RetStat;
			}else if(VarType = GetVariableType(Temp)){
				if((Pos = currLine.Parse(String(STATEMENT_ENDER), Temp, &Tok)) < 0){
					// Statement ender expected
					MAKEERR1(ERR03207, STATEMENT_ENDER);
				}
				currLine.Trim();
				if(currLine.GetLength() > 0){
					// Nothing expected after statement ender
					return CStatus(sERROR, ERR03208);
				}
				VarName = Temp;
        VarName.Trim();
				aVar.Name = VarName;
				aVar.SetType(VarType);
				aVar.Access = CurrProt;
				// Is this an OK variable name?
				RetStat = newDecl.RepClass->AddNewVariable(aVar);
        if(!RetStat) return RetStat;
			}else{
				// Unrecognized sequence
				return CStatus(sERROR, ERR03209);
			}
		}else{
			// Unrecognized sequence if not empty
			if(currLine.GetLength() > 0){
				return CStatus(sERROR, ERR03210);
			}
		}
  }while(bGo && Input->GetNextLine(aLine));  // Order here is important
*/








	/*
			CurrNode = GetNextStatement(CurrStat);
		if(!CurrNode){
			// Ending Brace was never found
			return STAT_ERR;
		}
		// REMINDER::: Make sure that the first statement is an open brace...
		if(CurrStat.Statement == FLOW_OPEN_BRACE){
			BCtr++;
			if(BCtr == 1){
				// If this is the first brace, begin at next statement
				BeginIndex = StatementList.GetCurrIndex() + 1;
			}
		}else if(CurrStat.Statement == FLOW_CLOSE_BRACE){
			BCtr--;
			if(BCtr < 0){
				// Opening Brace Never Found
				return STAT_ERR;
			}else if(BCtr == 0){
				// If this is the last brace, end at previous statement
				EndIndex = StatementList.GetCurrIndex() - 1;
				// Break Out
				bGo = 0;
			}
		*/

/*

	s.Trim();

	// Take care of open brace
	if(s.Parse(String(CLASS_OPEN_BRACE), Temp, &Tok) >= 0){
		ClassName = Temp;
		if(Tok == CLASS_OPEN_BRACE){
			inLine = CLASS_OPEN_BRACE;
			inLine = inLine + s;
		}else{
			inLine = s;
		}
		s = Temp;
		s.Trim();
	}

	// Take care of super class stuff
	if(s.Parse(String(CLASS_SUPER_SEPARATOR), Temp) >= 0){
		ClassName = Temp;
		s.Trim();
		if(s.Parse(String(CLASS_SUPER_PROT_SEPARATOR), Temp, &Tok) >= 0){
			if(Temp == CLASS_PUBLIC_STRING){
				newDecl.SuperProt = ACCESS_PUBLIC;
			}else if(Temp == CLASS_PROTECTED_STRING){
				newDecl.SuperProt = ACCESS_PROTECTED;
			}else if(Temp == CLASS_PRIVATE_STRING){
				newDecl.SuperProt = ACCESS_PRIVATE;
			}else{
				String sErr;
				sErr.Format("Class protection must be '%s', '%s', or '%s': '%s'", CLASS_PUBLIC_STRING, CLASS_PROTECTED_STRING, CLASS_PRIVATE_STRING, Temp.Str());
				return CStatus(sERROR, sErr);
			}
		}else{
			String sErr;
			sErr.Format("Class declaration expects: class 'classname' [: protection 'superclass']");
			return CStatus(sERROR, sErr);
		}
		s.Trim();
		newDecl.SuperName = s;
	}else if(s.Parse(String(CLASS_NAME_SEPARATORS), Temp, &Tok) >= 0){
		ClassName = Temp;
		s.Trim();
		if(s.GetLength() > 0){
			String sErr;
			sErr.Format("Class declaration expects: class 'classname' [: protection 'superclass']");
			return CStatus(sERROR, sErr);
		}
		//if(Tok == CLASS_OPEN_BRACE){
		//	inLine = CLASS_OPEN_BRACE;
		//	inLine = inLine + s;
		//}else{
		//	inLine = s;
		//}
	}else{
		ClassName = s;
		//inLine = "";
	}

	// Check for a valid name
	ClassName.Trim();
	newDecl.ClassName = ClassName;
	//s = ClassName;
	//if(s.Parse(CLASS_PAR_SEPARATORS, Temp, &Tok) >= 0){
	//	Temp.Trim();
	//	ClassName = Temp;

	//	s.Trim();
		
  //	if(s.Parse(CLASS_SUPER_PROT_SEPARATOR, Temp, &Tok) >= 0){
	//		Temp.Trim();
	//		s.Trim();
	//		newDecl.SuperName = Temp;
	//	}else{
	//		newDecl.SuperName = s;
	//		newDecl.SuperProt = ACCESS_PUBLIC;
	//	}
	//}
	//newDecl.ClassName = ClassName;
	*/
	return STAT_OK;  
}

CStatus CInterpreter::DefineUserClass(String& inLine, CClassDecl& newDecl)
{
	CStatus RetStat;
	RetStat = Engine->FindClassDecl(newDecl);
	if(!RetStat) return RetStat;

  SSI_BOOL bGo = 1;
	String currLine = inLine;  // inLine contains entire remainder if after a declare
	String Temp;
	String VarName;
	String Tok;
	SSI_INT64 Pos;
	SSI_INT64 Len;
	SSI_CHAR CurrProt = ACCESS_PUBLIC;  // Public by default
	SSI_INT64 VarType;
  CScriptLine aLine;
	CVariable aVar;
	CFunctionDecl funcDecl;

  while(bGo)
  {
    DeComment(currLine);
    currLine.Trim();

		if((Pos = currLine.Parse(CLASS_OPEN_BRACE, Temp)) >= 0){
      bGo = 0;
			currLine.Trim();
			aLine.Line = currLine;
      // Do something with remainder (currLine)
    }
    else{
      if(!(currLine == ""))
      {
        String Mess;
				MAKEERR1(ERR03213, CLASS_OPEN_BRACE);
      }
      if(!Input->GetNextLine(aLine))
      {
        String Mess;
        MAKEERR1(ERR03214, CLASS_OPEN_BRACE);
      }
      currLine = aLine.Line;
    }
  }

// May need to do something here regarding currLine and aLine

	bGo = 1;
	do
  {
		currLine = aLine.Line;
    DeComment(currLine);
    currLine.Trim();
		Len = currLine.GetLength();

		if((Pos = currLine.Parse(CLASS_CLOSE_BRACE, Temp, &Tok)) >= 0){
			bGo = 0;
			currLine.Trim();
			if(!(currLine == STATEMENT_ENDER)){
				//Statement ender expected at end of class
				MAKEERR1(ERR03203, STATEMENT_ENDER);
			}
			currLine = Temp;
		}

		if((Pos = currLine.Parse(CLASS_PROT_SEPARATOR, Temp, &Tok)) >= 0)
		{
			if(Pos != Len - 1){
				// Nothing can come after a protection decl
				return CStatus(sERROR, ERR03204);
			}
			if(Temp == CLASS_PUBLIC_STRING){
				CurrProt = ACCESS_PUBLIC;
			}else if(Temp == CLASS_PROTECTED_STRING){
				CurrProt = ACCESS_PROTECTED;
			}else if(Temp == CLASS_PRIVATE_STRING){
				CurrProt = ACCESS_PRIVATE;
			}else{
				// Public, private, or protected only
				String sErr;
				sErr.Format(ERR03205, CLASS_PUBLIC_STRING, CLASS_PROTECTED_STRING, CLASS_PRIVATE_STRING);
				return CStatus(sERROR, sErr);
			}
		}else if((Pos = currLine.Parse(CLASS_MEMBER_SEPARATOR, Temp, &Tok)) >= 0){
			if(Temp == FUNCTION_KEYWORD){
				RetStat = DeclareUserFunction(currLine, funcDecl);
				if(!RetStat) return RetStat;
				currLine.Trim();
				if(!(currLine == STATEMENT_ENDER)){
					// Statement ender expected
					MAKEERR1(ERR03206, STATEMENT_ENDER);
				}
				funcDecl.Access = CurrProt;
				RetStat = newDecl.RepClass->AddFunction(funcDecl);
				if(!RetStat) return RetStat;
			}else if(VarType = GetVariableType(Temp)){
				if((Pos = currLine.Parse(STATEMENT_ENDER, Temp, &Tok)) < 0){
					// Statement ender expected
					MAKEERR1(ERR03207, STATEMENT_ENDER);
				}
				currLine.Trim();
				if(currLine.GetLength() > 0){
					// Nothing expected after statement ender
					return CStatus(sERROR, ERR03208);
				}
				VarName = Temp;
        VarName.Trim();
				aVar.Name = VarName;
				aVar.SetType(VarType);
				aVar.Access = CurrProt;
				// Is this an OK variable name?
				RetStat = newDecl.RepClass->AddNewVariable(aVar);
        if(!RetStat) return RetStat;
			}else{
				// Unrecognized sequence
				return CStatus(sERROR, ERR03209);
			}
		}else{
			// Unrecognized sequence if not empty
			if(currLine.GetLength() > 0){
				return CStatus(sERROR, ERR03210);
			}
		}
  }while(bGo && Input->GetNextLine(aLine));  // Order here is important
	return STAT_OK;
}

SSI_BOOL CInterpreter::ChopEnder(String& Input)
{
	static String Ret;
	static String Tok;

	Input.SetQuoteState(1);
	if(Input.Parse(STATEMENT_ENDER, Ret, &Tok) >= 0)
  {
    Input = Ret;
		return 1;
  }
	return 0;
}

CStatus CInterpreter::DoClass(String& VarName, CVariable& RetVar, VarTree &ClassVars)
{
	String Name = VarName;
	String Ret;
	CVariable aVar;

	CData* aData = 0;

	// If there are any dot operators, parse them out and replace with variables
	Name.SetQuoteState(1);
	while(Name.Parse(CLASS_EVAL_SEPARATOR, Ret) >= 0){
		aVar.Name = Ret;
		aVar.SetType(dUNKNOWN);
		if(aData){
			if(!aData->GetVariable(aVar, this)){
				// Variable not a member of class
				MAKEERR2(ERR03323, aVar.Name.Str(), aData->DataName.Str());
			}
		}else{
			if(!Engine->GetVariable(aVar)){
				// Variable not found
				MAKEERR1(ERR03324, aVar.Name.Str());
			}
		}
		ClassVars.push_back(aVar);
		aData = &(aVar.GetWorkingData());
	}
	Name.SetQuoteState(0);

	// Count the variables in the list... if there are any, get the last one and work with it
	SSI_INT64 cnt = 0;
	VarItor Itor = ClassVars.begin();
	while(Itor != ClassVars.end()){
		cnt++;
		++Itor;
	}
	//if(Itor != ClassVars.end()){
	//	while(aVarNode){
	//		cnt++;
	//		aVarNode = aVarNode->next();
	//	}
	//}
	if(cnt > 0){
		Itor = ClassVars.end();
		--Itor;
		aVar = *Itor;
		//ClassVars[cnt-1]->Get(aVar);
		aData = &(aVar.GetWorkingData());
	}
	
	RetVar.Name = Name;
	RetVar.SetType(dUNKNOWN);   // Set the last variable in the list (not necessarily a class)
	if(aData){
		if(!aData->GetVariable(RetVar, this)){
			MAKEERR2(ERR03325, RetVar.Name.Str(), aData->DataName.Str());
		}
	}else{
		if(!Engine->GetVariable(RetVar)){
			return STAT_OK; // We want this to be OK, so it continues processing
		}
	}
	ClassVars.push_back(RetVar);
	return STAT_OK;
}


SSI_BOOL CInterpreter::IsClass(String& VarName)
{
	// Avoid 'real' numbers
	if(VarName.IsNumber()) return 0;

	String Ret;
	String RetName = VarName;
	if(RetName.Parse(CLASS_EVAL_SEPARATOR, Ret) >= 0){
		return 1;
	}
	return 0;
}

SSI_BOOL CInterpreter::IsClassFunction(String& TestString)
{
	String Name = TestString;
	String Ret;
	CVariable aVar;

	CData* aData = 0;

	
	while(Name.Parse(CLASS_EVAL_SEPARATOR, Ret) >= 0){
		aVar.Name = Ret;
		aVar.SetType(dUNKNOWN);
		if(aData){
			if(!aData->GetVariable(aVar, this)){
				// Check if it is a class function
				if(aData->IsFunction(aVar.Name)){
				}else{
					return 0;
				}
			}
		}else{
			if(!Engine->GetVariable(aVar)){
				// Check if it is a global function
				if(Engine->IsFunction(aVar.Name)){
				}else{
					return 0;
				}
			}
		}
		aData = &(aVar.GetWorkingData());
	}

	if(!aData) return 0;
	
	aData = &(aVar.GetWorkingData());
	return aData->IsFunction(Name);
}



/*CStatus CInterpreter::IsClass(String& VarName, String& RetName, CVariable& ClassVar)
{
	String Ret;
	RetName = VarName;
	CVariable aVar = ClassVar;
	if(RetName.Parse(CLASS_EVAL_SEPARATOR, Ret) >= 0){
      aVar.Name = Ret;
      aVar.SetType(dUNKNOWN);
			if(Engine->GetVariable(aVar)){
				ClassVar = aVar;
				return STAT_SUCCESS;
			}
			// Dot operator used on non-existing variable
			return STAT_ERR;
	}
	// STAT_SUCCESS must be returned for success
	return STAT_OK;
}*/

void CInterpreter::SetOutDisplay(ssi_stream* NewDisp)
{
  out = NewDisp;
	in = NewDisp;
}
void CInterpreter::SeparateToStatements(CScriptLine& InLine, CScriptStatementList& theList)
{
	CScriptStatement NewStatement;
	String s = InLine.Line;
	String Tokens = "#;{}";
	String Token;
	SSI_INT64 ind;
	NewStatement.LineID = InLine.ID;

	// Have to do this, else spaces will be bad...
	String sTrim = InLine.Line;
	sTrim.Trim();
	if(sTrim.GetLength() <= 0){
		// An empty line was entered... just add it to the list as is...
		NewStatement.Statement = InLine.Line;
		theList.AddStatement(NewStatement, 1);
		return;
	}

	s.SetQuoteState(1);  // Make sure it does not check within quotes
	while((ind = s.FindOneOf(Tokens)) >= 0){
		SSI_CHAR c = s.GetAt(ind);
		SSI_INT64 len = s.GetLength();
		if(c == '#'){
			NewStatement.Statement = s.Left(ind);
			theList.AddStatement(NewStatement);

			NewStatement.Statement = s.Right(len - ind);
			s = "";
		}else if(c == ';'){
			NewStatement.Statement = s.Left(ind+1);
			s = s.Right(len - ind - 1);
		}else if(c == '{'){
			NewStatement.Statement = s.Left(ind);
			theList.AddStatement(NewStatement);

			NewStatement.Statement.Format("%c", c);
			s = s.Right(len - ind - 1);
		}else if(c == '}'){
			NewStatement.Statement = s.Left(ind);
			theList.AddStatement(NewStatement);

			NewStatement.Statement.Format("%c", c);
			s = s.Right(len - ind - 1);
		}
		theList.AddStatement(NewStatement);
	}
	s.Trim();
	if(s.GetLength() > 0){
		NewStatement.Statement = s;
		theList.AddStatement(NewStatement);
	}

	s.SetQuoteState(0);
}

ScriptStatementNode* CInterpreter::GetNextStatement(CScriptStatement& TheStatement)
{
	ScriptStatementNode* Ret;
	ScriptStatementNode* CurrStat = 0;
	CScriptLine NewLine;
	SSI_INT64 CurrIndex;
	Ret = StatementList->GetNextStatement();
	if(!Ret){
		// Save the old index before getting new lines
		//CurrStat = StatementList.GetCurrIndex();
		CurrStat = StatementList->GetByIndex(-1);     // Get the last statement
		CurrIndex = StatementList->IndexOf(CurrStat); // Get the index of the last statement
		if(GetNextLine(NewLine)){
			
			// This will already be separated...
			//SeparateToStatements(NewLine, StatementList);
			Ret = StatementList->SetCurrIndex(CurrIndex);
			// Dont need this now...
			Ret = StatementList->GetNextStatement();
			if(!Ret) return 0;
			Ret->Get(TheStatement);
		}else{
			return 0;
		}
	}else{
		Ret->Get(TheStatement);
	}
	return Ret;
}

CStatus CInterpreter::BuildFunction(const String& Input, CFunction& theFunc)
{
	String Remainder;
	String Params;
	CStatus RetStat;
	CVariable aVar;
	VarTree pTree;
	VarItor pNode;

	String P = Input;
	P.SetQuoteState(1);

	if(!(RetStat = Parenthesize(P, Params, Remainder))) return RetStat;
	if(!(RetStat = Parameterize(Params, pTree))) return RetStat;
	VarItor Itor = pTree.begin();

  
	while(Itor != pTree.end()){
		//pNode->Get(aVar);
		aVar = *Itor;
		RetStat = theFunc.AddParam(aVar);
		if(!RetStat) return RetStat;
		//pNode = pNode->next();
		++Itor;
	}
	return STAT_OK;
}

SSI_BOOL CInterpreter::DisplayError(CStatus& aStat, String& sLineNum){
	SSI_BOOL Ret = 0;
	String PreBase;

  SSI_INT64 Warns = 0;
  SSI_INT64 Errs = 0;

#ifdef __STATUS_ERRORS__
  Warns = aStat.GetWarnCount();
  Errs = aStat.GetErrCount();
#else
  Engine->Environment->IncrementCounts(aStat);
  Warns = Engine->Environment->GetWarnCount();
  Errs = Engine->Environment->GetErrCount();
#endif

	if(aStat.GetState() == sERROR){
		PreBase.Format("** ERROR: (%d)", Errs);
		Ret = 0;
	}else if(aStat.GetState() == sWARNING){
		PreBase.Format("** WARNING: (%d)", Warns);
		Ret = 1;
	}else if(aStat.GetState() == sFAIL){
		PreBase.Format("** FAILURE: ");
		Ret = 0;
	}else{
		PreBase.Format("Custom message");
		Ret = 1;
	}
	String sOut = PreBase + " from '" + Input->GetInputName() + "' on line " + sLineNum + " - " + aStat.GetStatusMessage();

	if(aStat.GetState() == sERROR){
		out->ErrorDisp(sOut.Str(), 1);
	}else if(aStat.GetState() == sWARNING){
		out->WarningDisp(sOut.Str(), 1);
	}else if(aStat.GetState() == sFAIL){
		out->FailureDisp(sOut.Str(), 1);
	}else{
  	out->Disp(sOut.Str(), 1);
	}
  //Engine->Log(sOut);
	return Ret;

}

SSI_BOOL CInterpreter::DisplayMessage(String& sLineNum, String& Message){
	SSI_BOOL Ret = 1;
	String PreBase;
	PreBase.Format("** MESSAGE");
	String sOut = PreBase + " from '" + Input->GetInputName() + "' on Line " + sLineNum + " - " + Message;
	out->Disp(sOut.Str(), 1);
	return Ret;
}


SSI_BOOL CInterpreter::GetStopState(void)
{
	return bStopFlag;
}

void CInterpreter::SetStopFlag(void)
{
	bStopFlag = 1;
}

SSI_INT64 CInterpreter::QueryInput(void)
{
	ScriptStatementNode* sNode = StatementList->GetCurrentStatement();
	if(sNode == SSI_NULL){
		return 0;
	}
	CScriptStatement aStatement;
	sNode->Get(aStatement);
	return Input->Query(aStatement);

//					sNode = StatementList->GetCurrentStatement();
//					sNode->Get(aStatement);
					
//					ScriptNode* aNode = Input->GetByID(aStatement.LineID);
//					if(!aNode){
//						LineNum = -1;
//						sLineNum = "??";					
//					}else{
//						aNode->Get(aLine);
//						LineNum = aLine.LineNum;
//						sLineNum.Format("%d", LineNum);
//					}

					// Go to the end
//					StatementList->SetCurrIndex(-1);

//					Ret = DisplayError(aStat, sLineNum);
//					return Ret;

}


CStatus CInterpreter::GetFile(const String& FileName, String& Ret)
{
	int i = in->getLocalFile(FileName, Ret);
	if(i == 0){
		MAKEERR1(ERR02101, FileName.Str());
	}
	return STAT_OK;
}

CEngine* CInterpreter::GetEngine(void)
{
  return Engine;
}



